github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/cmd/evm/t8n_test.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"os"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/docker/docker/pkg/reexec"
    12  
    13  	"github.com/scroll-tech/go-ethereum/cmd/evm/internal/t8ntool"
    14  	"github.com/scroll-tech/go-ethereum/internal/cmdtest"
    15  )
    16  
    17  func TestMain(m *testing.M) {
    18  	// Run the app if we've been exec'd as "ethkey-test" in runEthkey.
    19  	reexec.Register("evm-test", func() {
    20  		if err := app.Run(os.Args); err != nil {
    21  			fmt.Fprintln(os.Stderr, err)
    22  			os.Exit(1)
    23  		}
    24  		os.Exit(0)
    25  	})
    26  	// check if we have been reexec'd
    27  	if reexec.Init() {
    28  		return
    29  	}
    30  	os.Exit(m.Run())
    31  }
    32  
    33  type testT8n struct {
    34  	*cmdtest.TestCmd
    35  }
    36  
    37  type t8nInput struct {
    38  	inAlloc  string
    39  	inTxs    string
    40  	inEnv    string
    41  	stFork   string
    42  	stReward string
    43  }
    44  
    45  func (args *t8nInput) get(base string) []string {
    46  	var out []string
    47  	if opt := args.inAlloc; opt != "" {
    48  		out = append(out, "--input.alloc")
    49  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
    50  	}
    51  	if opt := args.inTxs; opt != "" {
    52  		out = append(out, "--input.txs")
    53  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
    54  	}
    55  	if opt := args.inEnv; opt != "" {
    56  		out = append(out, "--input.env")
    57  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
    58  	}
    59  	if opt := args.stFork; opt != "" {
    60  		out = append(out, "--state.fork", opt)
    61  	}
    62  	if opt := args.stReward; opt != "" {
    63  		out = append(out, "--state.reward", opt)
    64  	}
    65  	return out
    66  }
    67  
    68  type t8nOutput struct {
    69  	alloc  bool
    70  	result bool
    71  	body   bool
    72  }
    73  
    74  func (args *t8nOutput) get() (out []string) {
    75  	if args.body {
    76  		out = append(out, "--output.body", "stdout")
    77  	} else {
    78  		out = append(out, "--output.body", "") // empty means ignore
    79  	}
    80  	if args.result {
    81  		out = append(out, "--output.result", "stdout")
    82  	} else {
    83  		out = append(out, "--output.result", "")
    84  	}
    85  	if args.alloc {
    86  		out = append(out, "--output.alloc", "stdout")
    87  	} else {
    88  		out = append(out, "--output.alloc", "")
    89  	}
    90  	return out
    91  }
    92  
    93  func TestT8n(t *testing.T) {
    94  	tt := new(testT8n)
    95  	tt.TestCmd = cmdtest.NewTestCmd(t, tt)
    96  	for i, tc := range []struct {
    97  		base        string
    98  		input       t8nInput
    99  		output      t8nOutput
   100  		expExitCode int
   101  		expOut      string
   102  	}{
   103  		{ // Test exit (3) on bad config
   104  			base: "./testdata/1",
   105  			input: t8nInput{
   106  				"alloc.json", "txs.json", "env.json", "Frontier+1346", "",
   107  			},
   108  			output:      t8nOutput{alloc: true, result: true},
   109  			expExitCode: 3,
   110  		},
   111  		{
   112  			base: "./testdata/1",
   113  			input: t8nInput{
   114  				"alloc.json", "txs.json", "env.json", "Byzantium", "",
   115  			},
   116  			output: t8nOutput{alloc: true, result: true},
   117  			expOut: "exp.json",
   118  		},
   119  		{ // blockhash test
   120  			base: "./testdata/3",
   121  			input: t8nInput{
   122  				"alloc.json", "txs.json", "env.json", "Berlin", "",
   123  			},
   124  			output: t8nOutput{alloc: true, result: true},
   125  			expOut: "exp.json",
   126  		},
   127  		{ // missing blockhash test
   128  			base: "./testdata/4",
   129  			input: t8nInput{
   130  				"alloc.json", "txs.json", "env.json", "Berlin", "",
   131  			},
   132  			output:      t8nOutput{alloc: true, result: true},
   133  			expExitCode: 4,
   134  		},
   135  		{ // Uncle test
   136  			base: "./testdata/5",
   137  			input: t8nInput{
   138  				"alloc.json", "txs.json", "env.json", "Byzantium", "0x80",
   139  			},
   140  			output: t8nOutput{alloc: true, result: true},
   141  			expOut: "exp.json",
   142  		},
   143  		{ // Sign json transactions
   144  			base: "./testdata/13",
   145  			input: t8nInput{
   146  				"alloc.json", "txs.json", "env.json", "London", "",
   147  			},
   148  			output: t8nOutput{body: true},
   149  			expOut: "exp.json",
   150  		},
   151  		{ // Already signed transactions
   152  			base: "./testdata/13",
   153  			input: t8nInput{
   154  				"alloc.json", "signed_txs.rlp", "env.json", "London", "",
   155  			},
   156  			output: t8nOutput{result: true},
   157  			expOut: "exp2.json",
   158  		},
   159  		{ // Difficulty calculation - no uncles
   160  			base: "./testdata/14",
   161  			input: t8nInput{
   162  				"alloc.json", "txs.json", "env.json", "London", "",
   163  			},
   164  			output: t8nOutput{result: true},
   165  			expOut: "exp.json",
   166  		},
   167  		{ // Difficulty calculation - with uncles
   168  			base: "./testdata/14",
   169  			input: t8nInput{
   170  				"alloc.json", "txs.json", "env.uncles.json", "London", "",
   171  			},
   172  			output: t8nOutput{result: true},
   173  			expOut: "exp2.json",
   174  		},
   175  		{ // Difficulty calculation - with ommers + Berlin
   176  			base: "./testdata/14",
   177  			input: t8nInput{
   178  				"alloc.json", "txs.json", "env.uncles.json", "Berlin", "",
   179  			},
   180  			output: t8nOutput{result: true},
   181  			expOut: "exp_berlin.json",
   182  		},
   183  		{ // Difficulty calculation on arrow glacier
   184  			base: "./testdata/19",
   185  			input: t8nInput{
   186  				"alloc.json", "txs.json", "env.json", "London", "",
   187  			},
   188  			output: t8nOutput{result: true},
   189  			expOut: "exp_london.json",
   190  		},
   191  		{ // Difficulty calculation on arrow glacier
   192  			base: "./testdata/19",
   193  			input: t8nInput{
   194  				"alloc.json", "txs.json", "env.json", "ArrowGlacier", "",
   195  			},
   196  			output: t8nOutput{result: true},
   197  			expOut: "exp_arrowglacier.json",
   198  		},
   199  		{ // Sign unprotected (pre-EIP155) transaction
   200  			base: "./testdata/23",
   201  			input: t8nInput{
   202  				"alloc.json", "txs.json", "env.json", "Berlin", "",
   203  			},
   204  			output: t8nOutput{result: true},
   205  			expOut: "exp.json",
   206  		},
   207  	} {
   208  
   209  		args := []string{"t8n"}
   210  		args = append(args, tc.output.get()...)
   211  		args = append(args, tc.input.get(tc.base)...)
   212  		var qArgs []string // quoted args for debugging purposes
   213  		for _, arg := range args {
   214  			if len(arg) == 0 {
   215  				qArgs = append(qArgs, `""`)
   216  			} else {
   217  				qArgs = append(qArgs, arg)
   218  			}
   219  		}
   220  		tt.Logf("args: %v\n", strings.Join(qArgs, " "))
   221  		tt.Run("evm-test", args...)
   222  		// Compare the expected output, if provided
   223  		if tc.expOut != "" {
   224  			want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
   225  			if err != nil {
   226  				t.Fatalf("test %d: could not read expected output: %v", i, err)
   227  			}
   228  			have := tt.Output()
   229  			ok, err := cmpJson(have, want)
   230  			switch {
   231  			case err != nil:
   232  				t.Fatalf("test %d, json parsing failed: %v", i, err)
   233  			case !ok:
   234  				t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
   235  			}
   236  		}
   237  		tt.WaitExit()
   238  		if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
   239  			t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
   240  		}
   241  	}
   242  }
   243  
   244  type t9nInput struct {
   245  	inTxs  string
   246  	stFork string
   247  }
   248  
   249  func (args *t9nInput) get(base string) []string {
   250  	var out []string
   251  	if opt := args.inTxs; opt != "" {
   252  		out = append(out, "--input.txs")
   253  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   254  	}
   255  	if opt := args.stFork; opt != "" {
   256  		out = append(out, "--state.fork", opt)
   257  	}
   258  	return out
   259  }
   260  
   261  func TestT9n(t *testing.T) {
   262  	tt := new(testT8n)
   263  	tt.TestCmd = cmdtest.NewTestCmd(t, tt)
   264  	for i, tc := range []struct {
   265  		base        string
   266  		input       t9nInput
   267  		expExitCode int
   268  		expOut      string
   269  	}{
   270  		{ // London txs on homestead
   271  			base: "./testdata/15",
   272  			input: t9nInput{
   273  				inTxs:  "signed_txs.rlp",
   274  				stFork: "Homestead",
   275  			},
   276  			expOut: "exp.json",
   277  		},
   278  		{ // London txs on London
   279  			base: "./testdata/15",
   280  			input: t9nInput{
   281  				inTxs:  "signed_txs.rlp",
   282  				stFork: "London",
   283  			},
   284  			expOut: "exp2.json",
   285  		},
   286  		{ // An RLP list (a blockheader really)
   287  			base: "./testdata/15",
   288  			input: t9nInput{
   289  				inTxs:  "blockheader.rlp",
   290  				stFork: "London",
   291  			},
   292  			expOut: "exp3.json",
   293  		},
   294  		{ // Transactions with too low gas
   295  			base: "./testdata/16",
   296  			input: t9nInput{
   297  				inTxs:  "signed_txs.rlp",
   298  				stFork: "London",
   299  			},
   300  			expOut: "exp.json",
   301  		},
   302  		{ // Transactions with value exceeding 256 bits
   303  			base: "./testdata/17",
   304  			input: t9nInput{
   305  				inTxs:  "signed_txs.rlp",
   306  				stFork: "London",
   307  			},
   308  			expOut: "exp.json",
   309  		},
   310  		{ // Invalid RLP
   311  			base: "./testdata/18",
   312  			input: t9nInput{
   313  				inTxs:  "invalid.rlp",
   314  				stFork: "London",
   315  			},
   316  			expExitCode: t8ntool.ErrorIO,
   317  		},
   318  	} {
   319  
   320  		args := []string{"t9n"}
   321  		args = append(args, tc.input.get(tc.base)...)
   322  
   323  		tt.Run("evm-test", args...)
   324  		tt.Logf("args:\n go run . %v\n", strings.Join(args, " "))
   325  		// Compare the expected output, if provided
   326  		if tc.expOut != "" {
   327  			want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
   328  			if err != nil {
   329  				t.Fatalf("test %d: could not read expected output: %v", i, err)
   330  			}
   331  			have := tt.Output()
   332  			ok, err := cmpJson(have, want)
   333  			switch {
   334  			case err != nil:
   335  				t.Logf(string(have))
   336  				t.Fatalf("test %d, json parsing failed: %v", i, err)
   337  			case !ok:
   338  				t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
   339  			}
   340  		}
   341  		tt.WaitExit()
   342  		if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
   343  			t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
   344  		}
   345  	}
   346  }
   347  
   348  type b11rInput struct {
   349  	inEnv       string
   350  	inOmmersRlp string
   351  	inTxsRlp    string
   352  	inClique    string
   353  	ethash      bool
   354  	ethashMode  string
   355  	ethashDir   string
   356  }
   357  
   358  func (args *b11rInput) get(base string) []string {
   359  	var out []string
   360  	if opt := args.inEnv; opt != "" {
   361  		out = append(out, "--input.header")
   362  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   363  	}
   364  	if opt := args.inOmmersRlp; opt != "" {
   365  		out = append(out, "--input.ommers")
   366  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   367  	}
   368  	if opt := args.inTxsRlp; opt != "" {
   369  		out = append(out, "--input.txs")
   370  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   371  	}
   372  	if opt := args.inClique; opt != "" {
   373  		out = append(out, "--seal.clique")
   374  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   375  	}
   376  	if args.ethash {
   377  		out = append(out, "--seal.ethash")
   378  	}
   379  	if opt := args.ethashMode; opt != "" {
   380  		out = append(out, "--seal.ethash.mode")
   381  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   382  	}
   383  	if opt := args.ethashDir; opt != "" {
   384  		out = append(out, "--seal.ethash.dir")
   385  		out = append(out, fmt.Sprintf("%v/%v", base, opt))
   386  	}
   387  	out = append(out, "--output.block")
   388  	out = append(out, "stdout")
   389  	return out
   390  }
   391  
   392  func TestB11r(t *testing.T) {
   393  	tt := new(testT8n)
   394  	tt.TestCmd = cmdtest.NewTestCmd(t, tt)
   395  	for i, tc := range []struct {
   396  		base        string
   397  		input       b11rInput
   398  		expExitCode int
   399  		expOut      string
   400  	}{
   401  		{ // unsealed block
   402  			base: "./testdata/20",
   403  			input: b11rInput{
   404  				inEnv:       "header.json",
   405  				inOmmersRlp: "ommers.json",
   406  				inTxsRlp:    "txs.rlp",
   407  			},
   408  			expOut: "exp.json",
   409  		},
   410  		{ // ethash test seal
   411  			base: "./testdata/21",
   412  			input: b11rInput{
   413  				inEnv:       "header.json",
   414  				inOmmersRlp: "ommers.json",
   415  				inTxsRlp:    "txs.rlp",
   416  			},
   417  			expOut: "exp.json",
   418  		},
   419  		{ // clique test seal
   420  			base: "./testdata/21",
   421  			input: b11rInput{
   422  				inEnv:       "header.json",
   423  				inOmmersRlp: "ommers.json",
   424  				inTxsRlp:    "txs.rlp",
   425  				inClique:    "clique.json",
   426  			},
   427  			expOut: "exp-clique.json",
   428  		},
   429  		{ // block with ommers
   430  			base: "./testdata/22",
   431  			input: b11rInput{
   432  				inEnv:       "header.json",
   433  				inOmmersRlp: "ommers.json",
   434  				inTxsRlp:    "txs.rlp",
   435  			},
   436  			expOut: "exp.json",
   437  		},
   438  	} {
   439  
   440  		args := []string{"b11r"}
   441  		args = append(args, tc.input.get(tc.base)...)
   442  
   443  		tt.Run("evm-test", args...)
   444  		tt.Logf("args:\n go run . %v\n", strings.Join(args, " "))
   445  		// Compare the expected output, if provided
   446  		if tc.expOut != "" {
   447  			want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
   448  			if err != nil {
   449  				t.Fatalf("test %d: could not read expected output: %v", i, err)
   450  			}
   451  			have := tt.Output()
   452  			ok, err := cmpJson(have, want)
   453  			switch {
   454  			case err != nil:
   455  				t.Logf(string(have))
   456  				t.Fatalf("test %d, json parsing failed: %v", i, err)
   457  			case !ok:
   458  				t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
   459  			}
   460  		}
   461  		tt.WaitExit()
   462  		if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
   463  			t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
   464  		}
   465  	}
   466  }
   467  
   468  // cmpJson compares the JSON in two byte slices.
   469  func cmpJson(a, b []byte) (bool, error) {
   470  	var j, j2 interface{}
   471  	if err := json.Unmarshal(a, &j); err != nil {
   472  		return false, err
   473  	}
   474  	if err := json.Unmarshal(b, &j2); err != nil {
   475  		return false, err
   476  	}
   477  	return reflect.DeepEqual(j2, j), nil
   478  }