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