| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- // Copyright 2021 The go-ethereum Authors
- // This file is part of go-ethereum.
- //
- // go-ethereum is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // go-ethereum is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
- package main
- import (
- "encoding/json"
- "fmt"
- "os"
- "reflect"
- "strings"
- "testing"
- "github.com/docker/docker/pkg/reexec"
- "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
- "github.com/ethereum/go-ethereum/internal/cmdtest"
- )
- func TestMain(m *testing.M) {
- // Run the app if we've been exec'd as "ethkey-test" in runEthkey.
- reexec.Register("evm-test", func() {
- if err := app.Run(os.Args); err != nil {
- fmt.Fprintln(os.Stderr, err)
- os.Exit(1)
- }
- os.Exit(0)
- })
- // check if we have been reexec'd
- if reexec.Init() {
- return
- }
- os.Exit(m.Run())
- }
- type testT8n struct {
- *cmdtest.TestCmd
- }
- type t8nInput struct {
- inAlloc string
- inTxs string
- inEnv string
- stFork string
- stReward string
- }
- func (args *t8nInput) get(base string) []string {
- var out []string
- if opt := args.inAlloc; opt != "" {
- out = append(out, "--input.alloc")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.inTxs; opt != "" {
- out = append(out, "--input.txs")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.inEnv; opt != "" {
- out = append(out, "--input.env")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.stFork; opt != "" {
- out = append(out, "--state.fork", opt)
- }
- if opt := args.stReward; opt != "" {
- out = append(out, "--state.reward", opt)
- }
- return out
- }
- type t8nOutput struct {
- alloc bool
- result bool
- body bool
- }
- func (args *t8nOutput) get() (out []string) {
- if args.body {
- out = append(out, "--output.body", "stdout")
- } else {
- out = append(out, "--output.body", "") // empty means ignore
- }
- if args.result {
- out = append(out, "--output.result", "stdout")
- } else {
- out = append(out, "--output.result", "")
- }
- if args.alloc {
- out = append(out, "--output.alloc", "stdout")
- } else {
- out = append(out, "--output.alloc", "")
- }
- return out
- }
- func TestT8n(t *testing.T) {
- tt := new(testT8n)
- tt.TestCmd = cmdtest.NewTestCmd(t, tt)
- for i, tc := range []struct {
- base string
- input t8nInput
- output t8nOutput
- expExitCode int
- expOut string
- }{
- { // Test exit (3) on bad config
- base: "./testdata/1",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Frontier+1346", "",
- },
- output: t8nOutput{alloc: true, result: true},
- expExitCode: 3,
- },
- {
- base: "./testdata/1",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Byzantium", "",
- },
- output: t8nOutput{alloc: true, result: true},
- expOut: "exp.json",
- },
- { // blockhash test
- base: "./testdata/3",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Berlin", "",
- },
- output: t8nOutput{alloc: true, result: true},
- expOut: "exp.json",
- },
- { // missing blockhash test
- base: "./testdata/4",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Berlin", "",
- },
- output: t8nOutput{alloc: true, result: true},
- expExitCode: 4,
- },
- { // Uncle test
- base: "./testdata/5",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Byzantium", "0x80",
- },
- output: t8nOutput{alloc: true, result: true},
- expOut: "exp.json",
- },
- { // Sign json transactions
- base: "./testdata/13",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "London", "",
- },
- output: t8nOutput{body: true},
- expOut: "exp.json",
- },
- { // Already signed transactions
- base: "./testdata/13",
- input: t8nInput{
- "alloc.json", "signed_txs.rlp", "env.json", "London", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp2.json",
- },
- { // Difficulty calculation - no uncles
- base: "./testdata/14",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "London", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp.json",
- },
- { // Difficulty calculation - with uncles
- base: "./testdata/14",
- input: t8nInput{
- "alloc.json", "txs.json", "env.uncles.json", "London", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp2.json",
- },
- { // Difficulty calculation - with ommers + Berlin
- base: "./testdata/14",
- input: t8nInput{
- "alloc.json", "txs.json", "env.uncles.json", "Berlin", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp_berlin.json",
- },
- { // Difficulty calculation on arrow glacier
- base: "./testdata/19",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "London", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp_london.json",
- },
- { // Difficulty calculation on arrow glacier
- base: "./testdata/19",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "ArrowGlacier", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp_arrowglacier.json",
- },
- { // Difficulty calculation on gray glacier
- base: "./testdata/19",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "GrayGlacier", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp_grayglacier.json",
- },
- { // Sign unprotected (pre-EIP155) transaction
- base: "./testdata/23",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Berlin", "",
- },
- output: t8nOutput{result: true},
- expOut: "exp.json",
- },
- { // Test post-merge transition
- base: "./testdata/24",
- input: t8nInput{
- "alloc.json", "txs.json", "env.json", "Merged", "",
- },
- output: t8nOutput{alloc: true, result: true},
- expOut: "exp.json",
- },
- { // Test post-merge transition where input is missing random
- base: "./testdata/24",
- input: t8nInput{
- "alloc.json", "txs.json", "env-missingrandom.json", "Merged", "",
- },
- output: t8nOutput{alloc: false, result: false},
- expExitCode: 3,
- },
- } {
- args := []string{"t8n"}
- args = append(args, tc.output.get()...)
- args = append(args, tc.input.get(tc.base)...)
- var qArgs []string // quoted args for debugging purposes
- for _, arg := range args {
- if len(arg) == 0 {
- qArgs = append(qArgs, `""`)
- } else {
- qArgs = append(qArgs, arg)
- }
- }
- tt.Logf("args: %v\n", strings.Join(qArgs, " "))
- tt.Run("evm-test", args...)
- // Compare the expected output, if provided
- if tc.expOut != "" {
- want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
- if err != nil {
- t.Fatalf("test %d: could not read expected output: %v", i, err)
- }
- have := tt.Output()
- ok, err := cmpJson(have, want)
- switch {
- case err != nil:
- t.Fatalf("test %d, json parsing failed: %v", i, err)
- case !ok:
- t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
- }
- }
- tt.WaitExit()
- if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
- t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
- }
- }
- }
- type t9nInput struct {
- inTxs string
- stFork string
- }
- func (args *t9nInput) get(base string) []string {
- var out []string
- if opt := args.inTxs; opt != "" {
- out = append(out, "--input.txs")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.stFork; opt != "" {
- out = append(out, "--state.fork", opt)
- }
- return out
- }
- func TestT9n(t *testing.T) {
- tt := new(testT8n)
- tt.TestCmd = cmdtest.NewTestCmd(t, tt)
- for i, tc := range []struct {
- base string
- input t9nInput
- expExitCode int
- expOut string
- }{
- { // London txs on homestead
- base: "./testdata/15",
- input: t9nInput{
- inTxs: "signed_txs.rlp",
- stFork: "Homestead",
- },
- expOut: "exp.json",
- },
- { // London txs on London
- base: "./testdata/15",
- input: t9nInput{
- inTxs: "signed_txs.rlp",
- stFork: "London",
- },
- expOut: "exp2.json",
- },
- { // An RLP list (a blockheader really)
- base: "./testdata/15",
- input: t9nInput{
- inTxs: "blockheader.rlp",
- stFork: "London",
- },
- expOut: "exp3.json",
- },
- { // Transactions with too low gas
- base: "./testdata/16",
- input: t9nInput{
- inTxs: "signed_txs.rlp",
- stFork: "London",
- },
- expOut: "exp.json",
- },
- { // Transactions with value exceeding 256 bits
- base: "./testdata/17",
- input: t9nInput{
- inTxs: "signed_txs.rlp",
- stFork: "London",
- },
- expOut: "exp.json",
- },
- { // Invalid RLP
- base: "./testdata/18",
- input: t9nInput{
- inTxs: "invalid.rlp",
- stFork: "London",
- },
- expExitCode: t8ntool.ErrorIO,
- },
- } {
- args := []string{"t9n"}
- args = append(args, tc.input.get(tc.base)...)
- tt.Run("evm-test", args...)
- tt.Logf("args:\n go run . %v\n", strings.Join(args, " "))
- // Compare the expected output, if provided
- if tc.expOut != "" {
- want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
- if err != nil {
- t.Fatalf("test %d: could not read expected output: %v", i, err)
- }
- have := tt.Output()
- ok, err := cmpJson(have, want)
- switch {
- case err != nil:
- t.Logf(string(have))
- t.Fatalf("test %d, json parsing failed: %v", i, err)
- case !ok:
- t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
- }
- }
- tt.WaitExit()
- if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
- t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
- }
- }
- }
- type b11rInput struct {
- inEnv string
- inOmmersRlp string
- inTxsRlp string
- inClique string
- ethash bool
- ethashMode string
- ethashDir string
- }
- func (args *b11rInput) get(base string) []string {
- var out []string
- if opt := args.inEnv; opt != "" {
- out = append(out, "--input.header")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.inOmmersRlp; opt != "" {
- out = append(out, "--input.ommers")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.inTxsRlp; opt != "" {
- out = append(out, "--input.txs")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.inClique; opt != "" {
- out = append(out, "--seal.clique")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if args.ethash {
- out = append(out, "--seal.ethash")
- }
- if opt := args.ethashMode; opt != "" {
- out = append(out, "--seal.ethash.mode")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- if opt := args.ethashDir; opt != "" {
- out = append(out, "--seal.ethash.dir")
- out = append(out, fmt.Sprintf("%v/%v", base, opt))
- }
- out = append(out, "--output.block")
- out = append(out, "stdout")
- return out
- }
- func TestB11r(t *testing.T) {
- tt := new(testT8n)
- tt.TestCmd = cmdtest.NewTestCmd(t, tt)
- for i, tc := range []struct {
- base string
- input b11rInput
- expExitCode int
- expOut string
- }{
- { // unsealed block
- base: "./testdata/20",
- input: b11rInput{
- inEnv: "header.json",
- inOmmersRlp: "ommers.json",
- inTxsRlp: "txs.rlp",
- },
- expOut: "exp.json",
- },
- { // ethash test seal
- base: "./testdata/21",
- input: b11rInput{
- inEnv: "header.json",
- inOmmersRlp: "ommers.json",
- inTxsRlp: "txs.rlp",
- },
- expOut: "exp.json",
- },
- { // clique test seal
- base: "./testdata/21",
- input: b11rInput{
- inEnv: "header.json",
- inOmmersRlp: "ommers.json",
- inTxsRlp: "txs.rlp",
- inClique: "clique.json",
- },
- expOut: "exp-clique.json",
- },
- { // block with ommers
- base: "./testdata/22",
- input: b11rInput{
- inEnv: "header.json",
- inOmmersRlp: "ommers.json",
- inTxsRlp: "txs.rlp",
- },
- expOut: "exp.json",
- },
- } {
- args := []string{"b11r"}
- args = append(args, tc.input.get(tc.base)...)
- tt.Run("evm-test", args...)
- tt.Logf("args:\n go run . %v\n", strings.Join(args, " "))
- // Compare the expected output, if provided
- if tc.expOut != "" {
- want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut))
- if err != nil {
- t.Fatalf("test %d: could not read expected output: %v", i, err)
- }
- have := tt.Output()
- ok, err := cmpJson(have, want)
- switch {
- case err != nil:
- t.Logf(string(have))
- t.Fatalf("test %d, json parsing failed: %v", i, err)
- case !ok:
- t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want))
- }
- }
- tt.WaitExit()
- if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
- t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
- }
- }
- }
- // cmpJson compares the JSON in two byte slices.
- func cmpJson(a, b []byte) (bool, error) {
- var j, j2 interface{}
- if err := json.Unmarshal(a, &j); err != nil {
- return false, err
- }
- if err := json.Unmarshal(b, &j2); err != nil {
- return false, err
- }
- return reflect.DeepEqual(j2, j), nil
- }
|