t8n_test.go 13 KB

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