1 // Aleth: Ethereum C++ client, tools and libraries.
2 // Copyright 2013-2019 Aleth Authors.
3 // Licensed under the GNU General Public License, Version 3.
4 #include "RLP.h"
5 using namespace std;
6 using namespace dev;
7
8 bytes dev::RLPNull = rlp("");
9 bytes dev::RLPEmptyList = rlpList();
10
11 namespace {
12
constructRLPSizeErrorInfo(size_t _actualSize,size_t _dataSize)13 errinfo_comment constructRLPSizeErrorInfo(size_t _actualSize, size_t _dataSize)
14 {
15 std::stringstream s;
16 s << "Actual size: " << _actualSize << ", data size: " << _dataSize;
17 return errinfo_comment(s.str());
18 }
19
20 }
21
RLP(bytesConstRef _d,Strictness _s)22 RLP::RLP(bytesConstRef _d, Strictness _s):
23 m_data(_d)
24 {
25 if ((_s & FailIfTooBig) && actualSize() < _d.size())
26 {
27 if (_s & ThrowOnFail)
28 BOOST_THROW_EXCEPTION(OversizeRLP() << constructRLPSizeErrorInfo(actualSize(), _d.size()));
29 else
30 m_data.reset();
31 }
32 if ((_s & FailIfTooSmall) && actualSize() > _d.size())
33 {
34 if (_s & ThrowOnFail)
35 BOOST_THROW_EXCEPTION(UndersizeRLP() << constructRLPSizeErrorInfo(actualSize(), _d.size()));
36 else
37 m_data.reset();
38 }
39 }
40
operator ++()41 RLP::iterator& RLP::iterator::operator++()
42 {
43 if (m_remaining)
44 {
45 m_currentItem.retarget(m_currentItem.next().data(), m_remaining);
46 m_currentItem = m_currentItem.cropped(0, sizeAsEncoded(m_currentItem));
47 m_remaining -= std::min<size_t>(m_remaining, m_currentItem.size());
48 }
49 else
50 m_currentItem.retarget(m_currentItem.next().data(), 0);
51 return *this;
52 }
53
iterator(RLP const & _parent,bool _begin)54 RLP::iterator::iterator(RLP const& _parent, bool _begin)
55 {
56 if (_begin && _parent.isList())
57 {
58 auto pl = _parent.payload();
59 m_currentItem = pl.cropped(0, sizeAsEncoded(pl));
60 m_remaining = pl.size() - m_currentItem.size();
61 }
62 else
63 {
64 m_currentItem = _parent.data().cropped(_parent.data().size());
65 m_remaining = 0;
66 }
67 }
68
operator [](size_t _i) const69 RLP RLP::operator[](size_t _i) const
70 {
71 if (_i < m_lastIndex)
72 {
73 // Get size of 0th item
74 m_lastEnd = sizeAsEncoded(payload());
75 // Set m_lastItem to 0th item data
76 m_lastItem = payload().cropped(0, m_lastEnd);
77 m_lastIndex = 0;
78 }
79 for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex)
80 {
81 // Get chunk of payload data starting right after m_lastItem
82 // This will be empty when we're out of bounds
83 m_lastItem = payload().cropped(m_lastEnd);
84 // Crop it to get the data of the next item
85 m_lastItem = m_lastItem.cropped(0, sizeAsEncoded(m_lastItem));
86 // Point m_lastEnd to next item
87 m_lastEnd += m_lastItem.size();
88 }
89 return RLP(m_lastItem, ThrowOnFail | FailIfTooSmall);
90 }
91
actualSize() const92 size_t RLP::actualSize() const
93 {
94 if (isNull())
95 return 0;
96 if (isSingleByte())
97 return 1;
98 if (isData() || isList())
99 return payloadOffset() + length();
100 return 0;
101 }
102
requireGood() const103 void RLP::requireGood() const
104 {
105 if (isNull())
106 BOOST_THROW_EXCEPTION(BadRLP());
107 byte n = m_data[0];
108 if (n != c_rlpDataImmLenStart + 1)
109 return;
110 if (m_data.size() < 2)
111 BOOST_THROW_EXCEPTION(BadRLP());
112 if (m_data[1] < c_rlpDataImmLenStart)
113 BOOST_THROW_EXCEPTION(BadRLP());
114 }
115
isInt() const116 bool RLP::isInt() const
117 {
118 if (isNull())
119 return false;
120 requireGood();
121 byte n = m_data[0];
122 if (n < c_rlpDataImmLenStart)
123 return !!n;
124 else if (n == c_rlpDataImmLenStart)
125 return true;
126 else if (n <= c_rlpDataIndLenZero)
127 {
128 if (m_data.size() <= 1)
129 BOOST_THROW_EXCEPTION(BadRLP());
130 return m_data[1] != 0;
131 }
132 else if (n < c_rlpListStart)
133 {
134 if (m_data.size() <= size_t(1 + n - c_rlpDataIndLenZero))
135 BOOST_THROW_EXCEPTION(BadRLP());
136 return m_data[1 + n - c_rlpDataIndLenZero] != 0;
137 }
138 else
139 return false;
140 return false;
141 }
142
length() const143 size_t RLP::length() const
144 {
145 if (isNull())
146 return 0;
147 requireGood();
148 size_t ret = 0;
149 byte const n = m_data[0];
150 if (n < c_rlpDataImmLenStart)
151 return 1;
152 else if (n <= c_rlpDataIndLenZero)
153 return n - c_rlpDataImmLenStart;
154 else if (n < c_rlpListStart)
155 {
156 if (m_data.size() <= size_t(n - c_rlpDataIndLenZero))
157 BOOST_THROW_EXCEPTION(BadRLP());
158 if (m_data.size() > 1)
159 if (m_data[1] == 0)
160 BOOST_THROW_EXCEPTION(BadRLP());
161 unsigned lengthSize = n - c_rlpDataIndLenZero;
162 if (lengthSize > sizeof(ret))
163 // We did not check, but would most probably not fit in our memory.
164 BOOST_THROW_EXCEPTION(UndersizeRLP());
165 // No leading zeroes.
166 if (!m_data[1])
167 BOOST_THROW_EXCEPTION(BadRLP());
168 for (unsigned i = 0; i < lengthSize; ++i)
169 ret = (ret << 8) | m_data[i + 1];
170 // Must be greater than the limit.
171 if (ret < c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes)
172 BOOST_THROW_EXCEPTION(BadRLP());
173 }
174 else if (n <= c_rlpListIndLenZero)
175 return n - c_rlpListStart;
176 else
177 {
178 unsigned lengthSize = n - c_rlpListIndLenZero;
179 if (m_data.size() <= lengthSize)
180 BOOST_THROW_EXCEPTION(BadRLP());
181 if (m_data.size() > 1)
182 if (m_data[1] == 0)
183 BOOST_THROW_EXCEPTION(BadRLP());
184 if (lengthSize > sizeof(ret))
185 // We did not check, but would most probably not fit in our memory.
186 BOOST_THROW_EXCEPTION(UndersizeRLP());
187 if (!m_data[1])
188 BOOST_THROW_EXCEPTION(BadRLP());
189 for (unsigned i = 0; i < lengthSize; ++i)
190 ret = (ret << 8) | m_data[i + 1];
191 if (ret < 0x100 - c_rlpListStart - c_rlpMaxLengthBytes)
192 BOOST_THROW_EXCEPTION(BadRLP());
193 }
194 // We have to be able to add payloadOffset to length without overflow.
195 // This rejects roughly 4GB-sized RLPs on some platforms.
196 if (ret >= std::numeric_limits<size_t>::max() - 0x100)
197 BOOST_THROW_EXCEPTION(UndersizeRLP());
198 return ret;
199 }
200
items() const201 size_t RLP::items() const
202 {
203 if (isList())
204 {
205 bytesConstRef d = payload();
206 size_t i = 0;
207 for (; d.size(); ++i)
208 d = d.cropped(sizeAsEncoded(d));
209 return i;
210 }
211 return 0;
212 }
213
appendRaw(bytesConstRef _s,size_t _itemCount)214 RLPStream& RLPStream::appendRaw(bytesConstRef _s, size_t _itemCount)
215 {
216 m_out.insert(m_out.end(), _s.begin(), _s.end());
217 noteAppended(_itemCount);
218 return *this;
219 }
220
noteAppended(size_t _itemCount)221 void RLPStream::noteAppended(size_t _itemCount)
222 {
223 if (!_itemCount)
224 return;
225 // cdebug << "noteAppended(" << _itemCount << ")";
226 while (m_listStack.size())
227 {
228 if (m_listStack.back().first < _itemCount)
229 BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large") << RequirementError((bigint)m_listStack.back().first, (bigint)_itemCount));
230 m_listStack.back().first -= _itemCount;
231 if (m_listStack.back().first)
232 break;
233 else
234 {
235 auto p = m_listStack.back().second;
236 m_listStack.pop_back();
237 size_t s = m_out.size() - p; // list size
238 auto brs = bytesRequired(s);
239 unsigned encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
240 // cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")";
241 auto os = m_out.size();
242 m_out.resize(os + encodeSize);
243 memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p);
244 if (s < c_rlpListImmLenCount)
245 m_out[p] = (byte)(c_rlpListStart + s);
246 else if (c_rlpListIndLenZero + brs <= 0xff)
247 {
248 m_out[p] = (byte)(c_rlpListIndLenZero + brs);
249 byte* b = &(m_out[p + brs]);
250 for (; s; s >>= 8)
251 *(b--) = (byte)s;
252 }
253 else
254 BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("itemCount too large for RLP"));
255 }
256 _itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list.
257 }
258 }
259
appendList(size_t _items)260 RLPStream& RLPStream::appendList(size_t _items)
261 {
262 // cdebug << "appendList(" << _items << ")";
263 if (_items)
264 m_listStack.push_back(std::make_pair(_items, m_out.size()));
265 else
266 appendList(bytes());
267 return *this;
268 }
269
appendList(bytesConstRef _rlp)270 RLPStream& RLPStream::appendList(bytesConstRef _rlp)
271 {
272 if (_rlp.size() < c_rlpListImmLenCount)
273 m_out.push_back((byte)(_rlp.size() + c_rlpListStart));
274 else
275 pushCount(_rlp.size(), c_rlpListIndLenZero);
276 appendRaw(_rlp, 1);
277 return *this;
278 }
279
append(bytesConstRef _s,bool _compact)280 RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
281 {
282 size_t s = _s.size();
283 byte const* d = _s.data();
284 if (_compact)
285 for (size_t i = 0; i < _s.size() && !*d; ++i, --s, ++d) {}
286
287 if (s == 1 && *d < c_rlpDataImmLenStart)
288 m_out.push_back(*d);
289 else
290 {
291 if (s < c_rlpDataImmLenCount)
292 m_out.push_back((byte)(s + c_rlpDataImmLenStart));
293 else
294 pushCount(s, c_rlpDataIndLenZero);
295 appendRaw(bytesConstRef(d, s), 0);
296 }
297 noteAppended();
298 return *this;
299 }
300
append(bigint _i)301 RLPStream& RLPStream::append(bigint _i)
302 {
303 if (!_i)
304 m_out.push_back(c_rlpDataImmLenStart);
305 else if (_i < c_rlpDataImmLenStart)
306 m_out.push_back((byte)_i);
307 else
308 {
309 unsigned br = bytesRequired(_i);
310 if (br < c_rlpDataImmLenCount)
311 m_out.push_back((byte)(br + c_rlpDataImmLenStart));
312 else
313 {
314 auto brbr = bytesRequired(br);
315 if (c_rlpDataIndLenZero + brbr > 0xff)
316 BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Number too large for RLP"));
317 m_out.push_back((byte)(c_rlpDataIndLenZero + brbr));
318 pushInt(br, brbr);
319 }
320 pushInt(_i, br);
321 }
322 noteAppended();
323 return *this;
324 }
325
pushCount(size_t _count,byte _base)326 void RLPStream::pushCount(size_t _count, byte _base)
327 {
328 auto br = bytesRequired(_count);
329 if (int(br) + _base > 0xff)
330 BOOST_THROW_EXCEPTION(RLPException() << errinfo_comment("Count too large for RLP"));
331 m_out.push_back((byte)(br + _base)); // max 8 bytes.
332 pushInt(_count, br);
333 }
334
streamOut(std::ostream & _out,dev::RLP const & _d,unsigned _depth=0)335 static void streamOut(std::ostream& _out, dev::RLP const& _d, unsigned _depth = 0)
336 {
337 if (_depth > 64)
338 _out << "<max-depth-reached>";
339 else if (_d.isNull())
340 _out << "null";
341 else if (_d.isInt())
342 _out << std::showbase << std::hex << std::nouppercase << _d.toInt<bigint>(RLP::LaissezFaire) << dec;
343 else if (_d.isData())
344 _out << escaped(_d.toString(), false);
345 else if (_d.isList())
346 {
347 _out << "[";
348 int j = 0;
349 for (auto i: _d)
350 {
351 _out << (j++ ? ", " : " ");
352 streamOut(_out, i, _depth + 1);
353 }
354 _out << " ]";
355 }
356 }
357
operator <<(std::ostream & _out,RLP const & _d)358 std::ostream& dev::operator<<(std::ostream& _out, RLP const& _d)
359 {
360 streamOut(_out, _d);
361 return _out;
362 }
363