github.com/theQRL/go-zond@v0.1.1/cmd/evm/t8n_test.go (about)

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