Fabcoin Core  0.16.2
P2P Digital Currency
rlp.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-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  cpp-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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
23 #include <fstream>
24 #include <sstream>
25 
26 #include <libdevcore/Log.h>
27 #include <libdevcore/RLP.h>
28 #include <libdevcore/Common.h>
29 #include <libdevcore/CommonIO.h>
30 #include <algorithm>
33 #include <boost/filesystem.hpp>
34 
35 using namespace std;
36 using namespace dev;
37 namespace js = json_spirit;
38 
39 namespace dev
40 {
41  namespace test
42  {
43  void buildRLP(js::mValue& _v, RLPStream& _rlp);
44  void checkRLPAgainstJson(js::mValue& v, RLP& u);
45  enum class RlpType
46  {
47  Valid,
48  Invalid,
49  Test
50  };
51 
52  void doRlpTests(json_spirit::mValue& v, bool _fillin)
53  {
54  string testname;
55  for (auto& i: v.get_obj())
56  {
57  js::mObject& o = i.second.get_obj();
58 
59  cnote << " " << i.first;
60  testname = "(" + i.first + ") ";
61 
62  BOOST_REQUIRE_MESSAGE(o.count("out") > 0, testname + "out not set!");
63  BOOST_REQUIRE_MESSAGE(!o["out"].is_null(), testname + "out is set to null!");
64 
65  if (_fillin)
66  {
67  try
68  {
69  bytes payloadToDecode = fromHex(o["out"].get_str());
70  RLP payload(payloadToDecode);
71  ostringstream() << payload;
72  o["in"] = "VALID";
73  }
74  catch (Exception const& _e)
75  {
76  cnote << "Exception: " << diagnostic_information(_e);
77  o["in"] = "INVALID";
78  }
79  catch (std::exception const& _e)
80  {
81  cnote << "rlp exception: " << _e.what();
82  o["in"] = "INVALID";
83  }
84  }
85  else
86  {
87  //Check Encode
88  BOOST_REQUIRE_MESSAGE(o.count("in") > 0, testname + "in not set!");
89  RlpType rlpType = RlpType::Test;
90  if (o["in"].type() == js::str_type)
91  {
92  if (o["in"].get_str() == "INVALID")
93  rlpType = RlpType::Invalid;
94  else if (o["in"].get_str() == "VALID")
95  rlpType = RlpType::Valid;
96  }
97 
98  if (rlpType == RlpType::Test)
99  {
100  RLPStream s;
101  dev::test::buildRLP(o["in"], s);
102  string computedText = toHex(s.out());
103 
104  string expectedText(o["out"].get_str());
105  transform(expectedText.begin(), expectedText.end(), expectedText.begin(), ::tolower );
106 
107  stringstream msg;
108  msg << "Encoding Failed: expected: " << expectedText << std::endl;
109  msg << " But Computed: " << computedText;
110  BOOST_CHECK_MESSAGE(expectedText == computedText, testname + msg.str());
111  }
112 
113  //Check Decode
114  // Uses the same test cases as encoding but in reverse.
115  // We read into the string of hex values, convert to bytes,
116  // and then compare the output structure to the json of the
117  // input object.
118  bool was_exception = false;
119  js::mValue& inputData = o["in"];
120  try
121  {
122  bytes payloadToDecode = fromHex(o["out"].get_str());
123  RLP payload(payloadToDecode);
124 
125  //attempt to read all the contents of RLP
126  ostringstream() << payload;
127 
128  if (rlpType == RlpType::Test)
129  dev::test::checkRLPAgainstJson(inputData, payload);
130  }
131  catch (Exception const& _e)
132  {
133  cnote << "Exception: " << diagnostic_information(_e);
134  was_exception = true;
135  }
136  catch (exception const& _e)
137  {
138  cnote << "rlp exception: " << _e.what();
139  was_exception = true;
140  }
141  catch (...)
142  {
143  was_exception = true;
144  }
145 
146  //Expect exception as input is INVALID
147  if (rlpType == RlpType::Invalid && was_exception)
148  continue;
149 
150  //Check that there was an exception as input is INVALID
151  if (rlpType == RlpType::Invalid && !was_exception)
152  BOOST_ERROR(testname + "Expected RLP Exception as rlp should be invalid!");
153 
154  //input is VALID check that there was no exceptions
155  if (was_exception)
156  BOOST_ERROR(testname + "Unexpected RLP Exception!");
157  }
158  }
159  }
160 
161  void buildRLP(js::mValue& _v, RLPStream& _rlp)
162  {
163  if (_v.type() == js::array_type)
164  {
165  RLPStream s;
166  for (auto& i: _v.get_array())
167  buildRLP(i, s);
168  _rlp.appendList(s.out());
169  }
170  else if (_v.type() == js::int_type)
171  _rlp.append(_v.get_uint64());
172  else if (_v.type() == js::str_type)
173  {
174  auto s = _v.get_str();
175  if (s.size() && s[0] == '#')
176  _rlp.append(bigint(s.substr(1)));
177  else
178  _rlp.append(s);
179  }
180  }
181 
183  {
184  if ( v.type() == js::str_type )
185  {
186  const string& expectedText = v.get_str();
187  if ( !expectedText.empty() && expectedText.front() == '#' )
188  {
189  // Deal with bigint instead of a raw string
190  string bigIntStr = expectedText.substr(1,expectedText.length()-1);
191  stringstream bintStream(bigIntStr);
192  bigint val;
193  bintStream >> val;
194  BOOST_CHECK( !u.isList() );
195  BOOST_CHECK( !u.isNull() );
196  BOOST_CHECK( u == val );
197  }
198  else
199  {
200  BOOST_CHECK( !u.isList() );
201  BOOST_CHECK( !u.isNull() );
202  BOOST_CHECK( u.isData() );
203  BOOST_CHECK( u.size() == expectedText.length() );
204  BOOST_CHECK( u == expectedText );
205  }
206  }
207  else if ( v.type() == js::int_type )
208  {
209  const int expectedValue = v.get_int();
210  BOOST_CHECK( u.isInt() );
211  BOOST_CHECK( !u.isList() );
212  BOOST_CHECK( !u.isNull() );
213  BOOST_CHECK( u == expectedValue );
214  }
215  else if ( v.type() == js::array_type )
216  {
217  BOOST_CHECK( u.isList() );
218  BOOST_CHECK( !u.isInt() );
219  BOOST_CHECK( !u.isData() );
220  js::mArray& arr = v.get_array();
221  BOOST_CHECK( u.itemCount() == arr.size() );
222  unsigned i;
223  for( i = 0; i < arr.size(); i++ )
224  {
225  RLP item = u[i];
226  checkRLPAgainstJson(arr[i], item);
227  }
228  }
229  else
230  {
231  BOOST_ERROR("Invalid Javascript object!");
232  }
233  }
234  }
235 }
236 
237 void runRlpTest(string _name, string _path)
238 {
239  string testPath = dev::test::getTestPath();
240  testPath += _path;
241 
242  try
243  {
244  cnote << "TEST " << _name << ":";
246  string s = asString(dev::contents(testPath + "/" + _name + ".json"));
247  BOOST_REQUIRE_MESSAGE(s.length() > 0, "Contents of " + testPath + "/" + _name + ".json is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
249  //Listener::notifySuiteStarted(_name);
250  dev::test::doRlpTests(v, false);
251  }
252  catch (Exception const& _e)
253  {
254  BOOST_ERROR("Failed test with Exception: " << diagnostic_information(_e));
255  }
256  catch (std::exception const& _e)
257  {
258  BOOST_ERROR("Failed test with Exception: " << _e.what());
259  }
260 }
261 
262 using namespace dev::test;
263 
265 
266 BOOST_AUTO_TEST_CASE(EmptyArrayList)
267 {
268  try
269  {
270  bytes payloadToDecode = fromHex("80");
271  RLP payload(payloadToDecode);
272  ostringstream() << payload;
273 
274  payloadToDecode = fromHex("с0");
275  RLP payload2(payloadToDecode);
276  ostringstream() << payload2;
277  }
278  catch (Exception const& _e)
279  {
280  BOOST_ERROR("(EmptyArrayList) Failed test with Exception: " << _e.what());
281  }
282  catch (exception const& _e)
283  {
284  BOOST_ERROR("(EmptyArrayList) Failed test with Exception: " << _e.what());
285  }
286 }
287 
288 BOOST_AUTO_TEST_CASE(invalidRLPtest)
289 {
290  runRlpTest("invalidRLPTest", "/RLPTests");
291 }
292 
294 {
295  runRlpTest("rlptest", "/RLPTests");
296 }
297 
299 {
300  string testPath = dev::test::getTestPath();
301  testPath += "/RLPTests/RandomRLPTests";
302 
303  vector<boost::filesystem::path> testFiles;
304  boost::filesystem::directory_iterator iterator(testPath);
305  for(; iterator != boost::filesystem::directory_iterator(); ++iterator)
306  if (boost::filesystem::is_regular_file(iterator->path()) && iterator->path().extension() == ".json")
307  testFiles.push_back(iterator->path());
308 
309  for (auto& path: testFiles)
310  {
311  try
312  {
313  cnote << "Testing ..." << path.filename();
315  string s = asString(dev::contents(path.string()));
316  BOOST_REQUIRE_MESSAGE(s.length() > 0, "Content of " + path.string() + " is empty. Have you cloned the 'tests' repo branch develop and set ETHEREUM_TEST_PATH to its path?");
318  //test::Listener::notifySuiteStarted(path.filename().string());
319  dev::test::doRlpTests(v, false);
320  }
321 
322  catch (Exception const& _e)
323  {
324  BOOST_ERROR(path.filename().string() + "Failed test with Exception: " << diagnostic_information(_e));
325  }
326  catch (std::exception const& _e)
327  {
328  BOOST_ERROR(path.filename().string() + "Failed test with Exception: " << _e.what());
329  }
330  }
331 }
332 
const Object & get_obj() const
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void runRlpTest(string _name, string _path)
Definition: rlp.cpp:237
std::string toHex(T const &_data, int _w=2, HexPrefix _prefix=HexPrefix::DontAdd)
Definition: CommonData.h:54
bool isNull() const
No value.
Definition: RLP.h:103
bool isInt() const
Integer value. Must not have a leading zero.
Definition: RLP.cpp:132
bool isList() const
List value.
Definition: RLP.h:112
void doRlpTests(json_spirit::mValue &v, bool _fillin)
Definition: rlp.cpp:52
size_t itemCount() const
Definition: RLP.h:118
RLPStream & append(unsigned _s)
Append given datum to the byte stream.
Definition: RLP.h:395
boost::multiprecision::number< boost::multiprecision::cpp_int_backend<>> bigint
Definition: Common.h:121
bytes const & out() const
Read the byte stream.
Definition: RLP.h:433
RlpType
Definition: rlp.cpp:45
const char * what() const noexceptoverride
Definition: Exceptions.h:42
boost::uint64_t get_uint64() const
std::hash for asio::adress
Definition: Common.h:323
Test mode – output information needed for test verification and benchmarking.
bool isData() const
String value.
Definition: RLP.h:109
void buildRLP(js::mValue &_v, RLPStream &_rlp)
Definition: rlp.cpp:161
void checkRLPAgainstJson(js::mValue &v, RLP &u)
Definition: rlp.cpp:182
const Array & get_array() const
Value_type type() const
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
bool read_string(const String_type &s, Value_type &value)
Base class for all exceptions.
Definition: Exceptions.h:39
mConfig::Array_type mArray
std::vector< byte > bytes
Definition: Common.h:75
std::string getTestPath()
Definition: Common.cpp:35
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
const String_type & get_str() const
mConfig::Object_type mObject
#define cnote
Definition: Log.h:303
#define BOOST_FIXTURE_TEST_SUITE(a, b)
Definition: object.cpp:14
PlatformStyle::TableColorType type
Definition: rpcconsole.cpp:61
#define BOOST_AUTO_TEST_SUITE_END()
Definition: object.cpp:16
BOOST_AUTO_TEST_CASE(EmptyArrayList)
Definition: rlp.cpp:266
std::string get_str(std::string::const_iterator begin, std::string::const_iterator end)
Class for writing to an RLP bytestream.
Definition: RLP.h:383
bytes contents(std::string const &_file)
Retrieve and returns the contents of the given file.
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
std::string asString(bytes const &_b)
Converts byte array to a string containing the same (binary) data.
Definition: CommonData.h:79
size_t size() const
Definition: RLP.h:122
Helper functions to work with json::spirit and test files.
#define BOOST_CHECK(expr)
Definition: object.cpp:17