rlp_test_util.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2015 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser 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. // The go-ethereum library 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 Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package tests
  17. import (
  18. "bytes"
  19. "encoding/hex"
  20. "errors"
  21. "fmt"
  22. "io"
  23. "math/big"
  24. "os"
  25. "strings"
  26. "github.com/ethereum/go-ethereum/rlp"
  27. )
  28. // RLPTest is the JSON structure of a single RLP test.
  29. type RLPTest struct {
  30. // If the value of In is "INVALID" or "VALID", the test
  31. // checks whether Out can be decoded into a value of
  32. // type interface{}.
  33. //
  34. // For other JSON values, In is treated as a driver for
  35. // calls to rlp.Stream. The test also verifies that encoding
  36. // In produces the bytes in Out.
  37. In interface{}
  38. // Out is a hex-encoded RLP value.
  39. Out string
  40. }
  41. // RunRLPTest runs the tests in the given file, skipping tests by name.
  42. func RunRLPTest(file string, skip []string) error {
  43. f, err := os.Open(file)
  44. if err != nil {
  45. return err
  46. }
  47. defer f.Close()
  48. return RunRLPTestWithReader(f, skip)
  49. }
  50. // RunRLPTest runs the tests encoded in r, skipping tests by name.
  51. func RunRLPTestWithReader(r io.Reader, skip []string) error {
  52. var tests map[string]*RLPTest
  53. if err := readJson(r, &tests); err != nil {
  54. return err
  55. }
  56. for _, s := range skip {
  57. delete(tests, s)
  58. }
  59. for name, test := range tests {
  60. if err := test.Run(); err != nil {
  61. return fmt.Errorf("test %q failed: %v", name, err)
  62. }
  63. }
  64. return nil
  65. }
  66. // Run executes the test.
  67. func (t *RLPTest) Run() error {
  68. outb, err := hex.DecodeString(t.Out)
  69. if err != nil {
  70. return fmt.Errorf("invalid hex in Out")
  71. }
  72. // Handle simple decoding tests with no actual In value.
  73. if t.In == "VALID" || t.In == "INVALID" {
  74. return checkDecodeInterface(outb, t.In == "VALID")
  75. }
  76. // Check whether encoding the value produces the same bytes.
  77. in := translateJSON(t.In)
  78. b, err := rlp.EncodeToBytes(in)
  79. if err != nil {
  80. return fmt.Errorf("encode failed: %v", err)
  81. }
  82. if !bytes.Equal(b, outb) {
  83. return fmt.Errorf("encode produced %x, want %x", b, outb)
  84. }
  85. // Test stream decoding.
  86. s := rlp.NewStream(bytes.NewReader(outb), 0)
  87. return checkDecodeFromJSON(s, in)
  88. }
  89. func checkDecodeInterface(b []byte, isValid bool) error {
  90. err := rlp.DecodeBytes(b, new(interface{}))
  91. switch {
  92. case isValid && err != nil:
  93. return fmt.Errorf("decoding failed: %v", err)
  94. case !isValid && err == nil:
  95. return fmt.Errorf("decoding of invalid value succeeded")
  96. }
  97. return nil
  98. }
  99. // translateJSON makes test json values encodable with RLP.
  100. func translateJSON(v interface{}) interface{} {
  101. switch v := v.(type) {
  102. case float64:
  103. return uint64(v)
  104. case string:
  105. if len(v) > 0 && v[0] == '#' { // # starts a faux big int.
  106. big, ok := new(big.Int).SetString(v[1:], 10)
  107. if !ok {
  108. panic(fmt.Errorf("bad test: bad big int: %q", v))
  109. }
  110. return big
  111. }
  112. return []byte(v)
  113. case []interface{}:
  114. new := make([]interface{}, len(v))
  115. for i := range v {
  116. new[i] = translateJSON(v[i])
  117. }
  118. return new
  119. default:
  120. panic(fmt.Errorf("can't handle %T", v))
  121. }
  122. }
  123. // checkDecodeFromJSON decodes from s guided by exp. exp drives the
  124. // Stream by invoking decoding operations (Uint, Big, List, ...) based
  125. // on the type of each value. The value decoded from the RLP stream
  126. // must match the JSON value.
  127. func checkDecodeFromJSON(s *rlp.Stream, exp interface{}) error {
  128. switch exp := exp.(type) {
  129. case uint64:
  130. i, err := s.Uint()
  131. if err != nil {
  132. return addStack("Uint", exp, err)
  133. }
  134. if i != exp {
  135. return addStack("Uint", exp, fmt.Errorf("result mismatch: got %d", i))
  136. }
  137. case *big.Int:
  138. big := new(big.Int)
  139. if err := s.Decode(&big); err != nil {
  140. return addStack("Big", exp, err)
  141. }
  142. if big.Cmp(exp) != 0 {
  143. return addStack("Big", exp, fmt.Errorf("result mismatch: got %d", big))
  144. }
  145. case []byte:
  146. b, err := s.Bytes()
  147. if err != nil {
  148. return addStack("Bytes", exp, err)
  149. }
  150. if !bytes.Equal(b, exp) {
  151. return addStack("Bytes", exp, fmt.Errorf("result mismatch: got %x", b))
  152. }
  153. case []interface{}:
  154. if _, err := s.List(); err != nil {
  155. return addStack("List", exp, err)
  156. }
  157. for i, v := range exp {
  158. if err := checkDecodeFromJSON(s, v); err != nil {
  159. return addStack(fmt.Sprintf("[%d]", i), exp, err)
  160. }
  161. }
  162. if err := s.ListEnd(); err != nil {
  163. return addStack("ListEnd", exp, err)
  164. }
  165. default:
  166. panic(fmt.Errorf("unhandled type: %T", exp))
  167. }
  168. return nil
  169. }
  170. func addStack(op string, val interface{}, err error) error {
  171. lines := strings.Split(err.Error(), "\n")
  172. lines = append(lines, fmt.Sprintf("\t%s: %v", op, val))
  173. return errors.New(strings.Join(lines, "\n"))
  174. }