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