github.com/theQRL/go-zond@v0.2.1/cmd/zvm/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/zvm/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 "zondkey-test" in runZondkey. 34 reexec.Register("zvm-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", "Shanghai+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", "Shanghai", "", 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", "Shanghai", "", 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", "Shanghai", "", 146 }, 147 output: t8nOutput{alloc: true, result: true}, 148 expExitCode: 4, 149 }, 150 { // Sign json transactions 151 base: "./testdata/13", 152 input: t8nInput{ 153 "alloc.json", "txs.json", "env.json", "Shanghai", "", 154 }, 155 output: t8nOutput{body: true}, 156 expOut: "exp.json", 157 }, 158 { // Already signed transactions 159 base: "./testdata/13", 160 input: t8nInput{ 161 "alloc.json", "signed_txs.rlp", "env.json", "Shanghai", "", 162 }, 163 output: t8nOutput{result: true}, 164 expOut: "exp2.json", 165 }, 166 { // Test post-merge transition 167 base: "./testdata/24", 168 input: t8nInput{ 169 "alloc.json", "txs.json", "env.json", "Shanghai", "", 170 }, 171 output: t8nOutput{alloc: true, result: true}, 172 expOut: "exp.json", 173 }, 174 { // Test post-merge transition where input is missing random 175 base: "./testdata/24", 176 input: t8nInput{ 177 "alloc.json", "txs.json", "env-missingrandom.json", "Shanghai", "", 178 }, 179 output: t8nOutput{alloc: false, result: false}, 180 expExitCode: 3, 181 }, 182 { // Test base fee calculation 183 base: "./testdata/25", 184 input: t8nInput{ 185 "alloc.json", "txs.json", "env.json", "Shanghai", "", 186 }, 187 output: t8nOutput{alloc: true, result: true}, 188 expOut: "exp.json", 189 }, 190 { // Test withdrawals transition 191 base: "./testdata/26", 192 input: t8nInput{ 193 "alloc.json", "txs.json", "env.json", "Shanghai", "", 194 }, 195 output: t8nOutput{alloc: true, result: true}, 196 expOut: "exp.json", 197 }, 198 } { 199 args := []string{"t8n"} 200 args = append(args, tc.output.get()...) 201 args = append(args, tc.input.get(tc.base)...) 202 var qArgs []string // quoted args for debugging purposes 203 for _, arg := range args { 204 if len(arg) == 0 { 205 qArgs = append(qArgs, `""`) 206 } else { 207 qArgs = append(qArgs, arg) 208 } 209 } 210 tt.Logf("args: %v\n", strings.Join(qArgs, " ")) 211 tt.Run("zvm-test", args...) 212 // Compare the expected output, if provided 213 if tc.expOut != "" { 214 file := fmt.Sprintf("%v/%v", tc.base, tc.expOut) 215 want, err := os.ReadFile(file) 216 if err != nil { 217 t.Fatalf("test %d: could not read expected output: %v", i, err) 218 } 219 have := tt.Output() 220 ok, err := cmpJson(have, want) 221 switch { 222 case err != nil: 223 t.Fatalf("test %d, file %v: json parsing failed: %v", i, file, err) 224 case !ok: 225 t.Fatalf("test %d, file %v: output wrong, have \n%v\nwant\n%v\n", i, file, string(have), string(want)) 226 } 227 } 228 tt.WaitExit() 229 if have, want := tt.ExitStatus(), tc.expExitCode; have != want { 230 t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want) 231 } 232 } 233 } 234 235 type t9nInput struct { 236 inTxs string 237 stFork string 238 } 239 240 func (args *t9nInput) get(base string) []string { 241 var out []string 242 if opt := args.inTxs; opt != "" { 243 out = append(out, "--input.txs") 244 out = append(out, fmt.Sprintf("%v/%v", base, opt)) 245 } 246 if opt := args.stFork; opt != "" { 247 out = append(out, "--state.fork", opt) 248 } 249 return out 250 } 251 252 func TestT9n(t *testing.T) { 253 tt := new(testT8n) 254 tt.TestCmd = cmdtest.NewTestCmd(t, tt) 255 for i, tc := range []struct { 256 base string 257 input t9nInput 258 expExitCode int 259 expOut string 260 }{ 261 { // txs on Shanghai 262 base: "./testdata/15", 263 input: t9nInput{ 264 inTxs: "signed_txs.rlp", 265 }, 266 expOut: "exp2.json", 267 }, 268 { // An RLP list (a blockheader really) 269 base: "./testdata/15", 270 input: t9nInput{ 271 inTxs: "blockheader.rlp", 272 }, 273 expOut: "exp3.json", 274 }, 275 { // Transactions with too low gas 276 base: "./testdata/16", 277 input: t9nInput{ 278 inTxs: "signed_txs.rlp", 279 }, 280 expOut: "exp.json", 281 }, 282 { // Transactions with value exceeding 256 bits 283 base: "./testdata/17", 284 input: t9nInput{ 285 inTxs: "signed_txs.rlp", 286 }, 287 expOut: "exp.json", 288 }, 289 { // Invalid RLP 290 base: "./testdata/18", 291 input: t9nInput{ 292 inTxs: "invalid.rlp", 293 }, 294 expExitCode: t8ntool.ErrorIO, 295 }, 296 } { 297 args := []string{"t9n"} 298 args = append(args, tc.input.get(tc.base)...) 299 300 tt.Run("zvm-test", args...) 301 tt.Logf("args:\n go run . %v\n", strings.Join(args, " ")) 302 // Compare the expected output, if provided 303 if tc.expOut != "" { 304 want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut)) 305 if err != nil { 306 t.Fatalf("test %d: could not read expected output: %v", i, err) 307 } 308 have := tt.Output() 309 ok, err := cmpJson(have, want) 310 switch { 311 case err != nil: 312 t.Logf(string(have)) 313 t.Fatalf("test %d, json parsing failed: %v", i, err) 314 case !ok: 315 t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want)) 316 } 317 } 318 tt.WaitExit() 319 if have, want := tt.ExitStatus(), tc.expExitCode; have != want { 320 t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want) 321 } 322 } 323 } 324 325 type b11rInput struct { 326 inEnv string 327 inWithdrawals string 328 inTxsRlp string 329 } 330 331 func (args *b11rInput) get(base string) []string { 332 var out []string 333 if opt := args.inEnv; opt != "" { 334 out = append(out, "--input.header") 335 out = append(out, fmt.Sprintf("%v/%v", base, opt)) 336 } 337 if opt := args.inWithdrawals; opt != "" { 338 out = append(out, "--input.withdrawals") 339 out = append(out, fmt.Sprintf("%v/%v", base, opt)) 340 } 341 if opt := args.inTxsRlp; opt != "" { 342 out = append(out, "--input.txs") 343 out = append(out, fmt.Sprintf("%v/%v", base, opt)) 344 } 345 out = append(out, "--output.block") 346 out = append(out, "stdout") 347 return out 348 } 349 350 func TestB11r(t *testing.T) { 351 tt := new(testT8n) 352 tt.TestCmd = cmdtest.NewTestCmd(t, tt) 353 for i, tc := range []struct { 354 base string 355 input b11rInput 356 expExitCode int 357 expOut string 358 }{ 359 { // unsealed block 360 base: "./testdata/20", 361 input: b11rInput{ 362 inEnv: "header.json", 363 inTxsRlp: "txs.rlp", 364 }, 365 expOut: "exp.json", 366 }, 367 { // block with withdrawals 368 base: "./testdata/27", 369 input: b11rInput{ 370 inEnv: "header.json", 371 inWithdrawals: "withdrawals.json", 372 inTxsRlp: "txs.rlp", 373 }, 374 expOut: "exp.json", 375 }, 376 } { 377 args := []string{"b11r"} 378 args = append(args, tc.input.get(tc.base)...) 379 380 tt.Run("zvm-test", args...) 381 tt.Logf("args:\n go run . %v\n", strings.Join(args, " ")) 382 // Compare the expected output, if provided 383 if tc.expOut != "" { 384 want, err := os.ReadFile(fmt.Sprintf("%v/%v", tc.base, tc.expOut)) 385 if err != nil { 386 t.Fatalf("test %d: could not read expected output: %v", i, err) 387 } 388 have := tt.Output() 389 ok, err := cmpJson(have, want) 390 switch { 391 case err != nil: 392 t.Logf(string(have)) 393 t.Fatalf("test %d, json parsing failed: %v", i, err) 394 case !ok: 395 t.Fatalf("test %d: output wrong, have \n%v\nwant\n%v\n", i, string(have), string(want)) 396 } 397 } 398 tt.WaitExit() 399 if have, want := tt.ExitStatus(), tc.expExitCode; have != want { 400 t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want) 401 } 402 } 403 } 404 405 // cmpJson compares the JSON in two byte slices. 406 func cmpJson(a, b []byte) (bool, error) { 407 var j, j2 interface{} 408 if err := json.Unmarshal(a, &j); err != nil { 409 return false, err 410 } 411 if err := json.Unmarshal(b, &j2); err != nil { 412 return false, err 413 } 414 return reflect.DeepEqual(j2, j), nil 415 }