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 */
22 #include "RLP.h"
23 using namespace std;
24 using namespace dev;
25 
28 
29 RLP::RLP(bytesConstRef _d, Strictness _s):
30  m_data(_d)
31 {
32  if ((_s & FailIfTooBig) && actualSize() < _d.size())
33  {
34  if (_s & ThrowOnFail)
35  BOOST_THROW_EXCEPTION(OversizeRLP());
36  else
37  m_data.reset();
38  }
39  if ((_s & FailIfTooSmall) && actualSize() > _d.size())
40  {
41  if (_s & ThrowOnFail)
42  BOOST_THROW_EXCEPTION(UndersizeRLP());
43  else
44  m_data.reset();
45  }
46 }
47 
49 {
50  if (m_remaining)
51  {
52  m_currentItem.retarget(m_currentItem.next().data(), m_remaining);
53  m_currentItem = m_currentItem.cropped(0, sizeAsEncoded(m_currentItem));
54  m_remaining -= std::min<size_t>(m_remaining, m_currentItem.size());
55  }
56  else
57  m_currentItem.retarget(m_currentItem.next().data(), 0);
58  return *this;
59 }
60 
61 RLP::iterator::iterator(RLP const& _parent, bool _begin)
62 {
63  if (_begin && _parent.isList())
64  {
65  auto pl = _parent.payload();
66  m_currentItem = pl.cropped(0, sizeAsEncoded(pl));
67  m_remaining = pl.size() - m_currentItem.size();
68  }
69  else
70  {
71  m_currentItem = _parent.data().cropped(_parent.data().size());
72  m_remaining = 0;
73  }
74 }
75 
76 RLP RLP::operator[](size_t _i) const
77 {
78  if (_i < m_lastIndex)
79  {
82  m_lastIndex = 0;
83  }
84  for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex)
85  {
89  }
91 }
92 
93 RLPs RLP::toList(int _flags) const
94 {
95  RLPs ret;
96  if (!isList())
97  {
98  if (_flags & ThrowOnFail)
99  BOOST_THROW_EXCEPTION(BadCast());
100  else
101  return ret;
102  }
103  for (auto const& i: *this)
104  ret.push_back(i);
105  return ret;
106 }
107 
108 size_t RLP::actualSize() const
109 {
110  if (isNull())
111  return 0;
112  if (isSingleByte())
113  return 1;
114  if (isData() || isList())
115  return payloadOffset() + length();
116  return 0;
117 }
118 
119 void RLP::requireGood() const
120 {
121  if (isNull())
122  BOOST_THROW_EXCEPTION(BadRLP());
123  byte n = m_data[0];
124  if (n != c_rlpDataImmLenStart + 1)
125  return;
126  if (m_data.size() < 2)
127  BOOST_THROW_EXCEPTION(BadRLP());
128  if (m_data[1] < c_rlpDataImmLenStart)
129  BOOST_THROW_EXCEPTION(BadRLP());
130 }
131 
132 bool RLP::isInt() const
133 {
134  if (isNull())
135  return false;
136  requireGood();
137  byte n = m_data[0];
138  if (n < c_rlpDataImmLenStart)
139  return !!n;
140  else if (n == c_rlpDataImmLenStart)
141  return true;
142  else if (n <= c_rlpDataIndLenZero)
143  {
144  if (m_data.size() <= 1)
145  BOOST_THROW_EXCEPTION(BadRLP());
146  return m_data[1] != 0;
147  }
148  else if (n < c_rlpListStart)
149  {
150  if (m_data.size() <= size_t(1 + n - c_rlpDataIndLenZero))
151  BOOST_THROW_EXCEPTION(BadRLP());
152  return m_data[1 + n - c_rlpDataIndLenZero] != 0;
153  }
154  else
155  return false;
156  return false;
157 }
158 
159 size_t RLP::length() const
160 {
161  if (isNull())
162  return 0;
163  requireGood();
164  size_t ret = 0;
165  byte const n = m_data[0];
166  if (n < c_rlpDataImmLenStart)
167  return 1;
168  else if (n <= c_rlpDataIndLenZero)
169  return n - c_rlpDataImmLenStart;
170  else if (n < c_rlpListStart)
171  {
172  if (m_data.size() <= size_t(n - c_rlpDataIndLenZero))
173  BOOST_THROW_EXCEPTION(BadRLP());
174  if (m_data.size() > 1)
175  if (m_data[1] == 0)
176  BOOST_THROW_EXCEPTION(BadRLP());
177  unsigned lengthSize = n - c_rlpDataIndLenZero;
178  if (lengthSize > sizeof(ret))
179  // We did not check, but would most probably not fit in our memory.
180  BOOST_THROW_EXCEPTION(UndersizeRLP());
181  // No leading zeroes.
182  if (!m_data[1])
183  BOOST_THROW_EXCEPTION(BadRLP());
184  for (unsigned i = 0; i < lengthSize; ++i)
185  ret = (ret << 8) | m_data[i + 1];
186  // Must be greater than the limit.
187  if (ret < c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes)
188  BOOST_THROW_EXCEPTION(BadRLP());
189  }
190  else if (n <= c_rlpListIndLenZero)
191  return n - c_rlpListStart;
192  else
193  {
194  unsigned lengthSize = n - c_rlpListIndLenZero;
195  if (m_data.size() <= lengthSize)
196  BOOST_THROW_EXCEPTION(BadRLP());
197  if (m_data.size() > 1)
198  if (m_data[1] == 0)
199  BOOST_THROW_EXCEPTION(BadRLP());
200  if (lengthSize > sizeof(ret))
201  // We did not check, but would most probably not fit in our memory.
202  BOOST_THROW_EXCEPTION(UndersizeRLP());
203  if (!m_data[1])
204  BOOST_THROW_EXCEPTION(BadRLP());
205  for (unsigned i = 0; i < lengthSize; ++i)
206  ret = (ret << 8) | m_data[i + 1];
207  if (ret < 0x100 - c_rlpListStart - c_rlpMaxLengthBytes)
208  BOOST_THROW_EXCEPTION(BadRLP());
209  }
210  // We have to be able to add payloadOffset to length without overflow.
211  // This rejects roughly 4GB-sized RLPs on some platforms.
212  if (ret >= std::numeric_limits<size_t>::max() - 0x100)
213  BOOST_THROW_EXCEPTION(UndersizeRLP());
214  return ret;
215 }
216 
217 size_t RLP::items() const
218 {
219  if (isList())
220  {
221  bytesConstRef d = payload();
222  size_t i = 0;
223  for (; d.size(); ++i)
224  d = d.cropped(sizeAsEncoded(d));
225  return i;
226  }
227  return 0;
228 }
229 
231 {
232  m_out.insert(m_out.end(), _s.begin(), _s.end());
233  noteAppended(_itemCount);
234  return *this;
235 }
236 
237 void RLPStream::noteAppended(size_t _itemCount)
238 {
239  if (!_itemCount)
240  return;
241 // cdebug << "noteAppended(" << _itemCount << ")";
242  while (m_listStack.size())
243  {
244  if (m_listStack.back().first < _itemCount)
245  BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount));
246  m_listStack.back().first -= _itemCount;
247  if (m_listStack.back().first)
248  break;
249  else
250  {
251  auto p = m_listStack.back().second;
252  m_listStack.pop_back();
253  size_t s = m_out.size() - p; // list size
254  auto brs = bytesRequired(s);
255  unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
256 // cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")";
257  auto os = m_out.size();
258  m_out.resize(os + encodeSize);
259  memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p);
260  if (s < c_rlpListImmLenCount)
261  m_out[p] = (byte)(c_rlpListStart + s);
262  else if (c_rlpListIndLenZero + brs <= 0xff)
263  {
264  m_out[p] = (byte)(c_rlpListIndLenZero + brs);
265  byte* b = &(m_out[p + brs]);
266  for (; s; s >>= 8)
267  *(b--) = (byte)s;
268  }
269  else
270  BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large for RLP"));
271  }
272  _itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list.
273  }
274 }
275 
277 {
278 // cdebug << "appendList(" << _items << ")";
279  if (_items)
280  m_listStack.push_back(std::make_pair(_items, m_out.size()));
281  else
282  appendList(bytes());
283  return *this;
284 }
285 
287 {
288  if (_rlp.size() < c_rlpListImmLenCount)
289  m_out.push_back((byte)(_rlp.size() + c_rlpListStart));
290  else
291  pushCount(_rlp.size(), c_rlpListIndLenZero);
292  appendRaw(_rlp, 1);
293  return *this;
294 }
295 
297 {
298  size_t s = _s.size();
299  byte const* d = _s.data();
300  if (_compact)
301  for (size_t i = 0; i < _s.size() && !*d; ++i, --s, ++d) {}
302 
303  if (s == 1 && *d < c_rlpDataImmLenStart)
304  m_out.push_back(*d);
305  else
306  {
307  if (s < c_rlpDataImmLenCount)
308  m_out.push_back((byte)(s + c_rlpDataImmLenStart));
309  else
310  pushCount(s, c_rlpDataIndLenZero);
311  appendRaw(bytesConstRef(d, s), 0);
312  }
313  noteAppended();
314  return *this;
315 }
316 
318 {
319  if (!_i)
320  m_out.push_back(c_rlpDataImmLenStart);
321  else if (_i < c_rlpDataImmLenStart)
322  m_out.push_back((byte)_i);
323  else
324  {
325  unsigned br = bytesRequired(_i);
326  if (br < c_rlpDataImmLenCount)
327  m_out.push_back((byte)(br + c_rlpDataImmLenStart));
328  else
329  {
330  auto brbr = bytesRequired(br);
331  if (c_rlpDataIndLenZero + brbr > 0xff)
332  BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Number too large for RLP"));
333  m_out.push_back((byte)(c_rlpDataIndLenZero + brbr));
334  pushInt(br, brbr);
335  }
336  pushInt(_i, br);
337  }
338  noteAppended();
339  return *this;
340 }
341 
342 void RLPStream::pushCount(size_t _count, byte _base)
343 {
344  auto br = bytesRequired(_count);
345  if (int(br) + _base > 0xff)
346  BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Count too large for RLP"));
347  m_out.push_back((byte)(br + _base)); // max 8 bytes.
348  pushInt(_count, br);
349 }
350 
351 static void streamOut(std::ostream& _out, dev::RLP const& _d, unsigned _depth = 0)
352 {
353  if (_depth > 64)
354  _out << "<max-depth-reached>";
355  else if (_d.isNull())
356  _out << "null";
357  else if (_d.isInt())
358  _out << std::showbase << std::hex << std::nouppercase << _d.toInt<bigint>(RLP::LaissezFaire) << dec;
359  else if (_d.isData())
360  _out << escaped(_d.toString(), false);
361  else if (_d.isList())
362  {
363  _out << "[";
364  int j = 0;
365  for (auto i: _d)
366  {
367  _out << (j++ ? ", " : " ");
368  streamOut(_out, i, _depth + 1);
369  }
370  _out << " ]";
371  }
372 }
373 
374 std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d)
375 {
376  streamOut(_out, _d);
377  return _out;
378 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
bool isNull() const
No value.
Definition: RLP.h:103
uint8_t byte
Definition: Common.h:57
bool isInt() const
Integer value. Must not have a leading zero.
Definition: RLP.cpp:132
bool isList() const
List value.
Definition: RLP.h:112
bytes rlp(_T _t)
Export a single item in RLP format, returning a byte array.
Definition: RLP.h:467
bytesConstRef data() const
The bare data of the RLP.
Definition: RLP.h:97
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
void requireGood() const
Throws if is non-canonical data (i.e. single byte done in two bytes that could be done in one)...
Definition: RLP.cpp:119
RLP operator[](size_t _i) const
Subscript operator.
Definition: RLP.cpp:76
unsigned bytesRequired(T _i)
Determine bytes required to encode the given integer value.
Definition: CommonData.h:205
std::hash for asio::adress
Definition: Common.h:323
size_t items() const
Definition: RLP.cpp:217
bool isData() const
String value.
Definition: RLP.h:109
void pushCount(size_t _count, byte _offset)
Push the node-type byte (using _base) along with the item count _count.
Definition: RLP.cpp:342
vector_ref< _T > cropped(size_t _begin, size_t _count) const
Definition: vector_ref.h:62
RLP()
Construct a null node.
Definition: RLP.h:82
std::string escaped(std::string const &_s, bool _all=true)
Escapes a string into the C-string representation.
Definition: CommonData.cpp:60
static size_t sizeAsEncoded(bytesConstRef _data)
Definition: RLP.h:350
bytes RLPNull
The empty string in RLP format.
Definition: RLP.cpp:26
unsigned lengthSize() const
Definition: RLP.h:338
ExecStats::duration max
Definition: ExecStats.cpp:36
bytesConstRef payload() const
Definition: RLP.h:321
std::vector< byte > bytes
Definition: Common.h:75
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
RLPStream & appendList(size_t _items)
Appends a list.
Definition: RLP.cpp:276
bytesConstRef m_data
Our byte data.
Definition: RLP.h:353
void noteAppended(size_t _itemCount=1)
Definition: RLP.cpp:237
#define b(i, j)
size_t size() const
Definition: vector_ref.h:55
RLPs toList(int _flags=Strict) const
Converts to RLPs collection object. Useful if you need random access to sub items or will iterate ove...
Definition: RLP.cpp:93
bytes rlpList()
Export a list of items in RLP format, returning a byte array.
Definition: RLP.h:470
std::ostream & operator<<(std::ostream &_out, bytes const &_e)
Definition: CommonIO.h:80
bytesConstRef m_lastItem
Definition: RLP.h:358
_T * data() const
Definition: vector_ref.h:51
iterator & operator++()
Definition: RLP.cpp:48
bool isSingleByte() const
Single-byte data payload.
Definition: RLP.h:335
Base class for all RLP exceptions.
Definition: Exceptions.h:51
size_t actualSize() const
Definition: RLP.cpp:108
size_t length() const
Definition: RLP.cpp:159
boost::error_info< struct tag_comment, std::string > errinfo_comment
Definition: Assertions.h:78
uint8_t byte
Definition: Common.h:10
Iterator class for iterating through items of RLP list.
Definition: RLP.h:147
size_t m_lastIndex
The list-indexing cache.
Definition: RLP.h:356
std::string toString(int _flags=LaissezFaire) const
Converts to string.
Definition: RLP.h:199
size_t payloadOffset() const
Definition: RLP.h:344
#define d(i)
Definition: sha.cpp:732
boost::tuple< errinfo_required, errinfo_got > RequirementError
Definition: Exceptions.h:80
_T toInt(int _flags=Strict) const
Converts to int of type given; if isString(), decodes as big-endian bytestream.
Definition: RLP.h:275
void * memmove(void *a, const void *b, size_t c)
Class for writing to an RLP bytestream.
Definition: RLP.h:383
RLPStream & appendRaw(bytesConstRef _rlp, size_t _itemCount=1)
Appends raw (pre-serialised) RLP data. Use with caution.
Definition: RLP.cpp:230
std::vector< RLP > RLPs
Definition: RLP.h:40
Class for interpreting Recursive Linear-Prefix Data.
Definition: RLP.h:64
size_t m_lastEnd
Definition: RLP.h:357
int Strictness
Definition: RLP.h:79
bytes RLPEmptyList
The empty list in RLP format.
Definition: RLP.cpp:27