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 }