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 }