Browse Source

Latest RLP standard. Lists specify length rather than itemCount.

cl-refactor
Gav Wood 11 years ago
parent
commit
0abd91d551
  1. 4
      libethereum/MemTrie.cpp
  2. 113
      libethereum/RLP.cpp
  3. 50
      libethereum/RLP.h
  4. 9
      libethereum/TrieDB.h
  5. 6
      libethereum/TrieHash.cpp
  6. 10
      test/main.cpp
  7. 6
      test/rlp.cpp

4
libethereum/MemTrie.cpp

@ -434,12 +434,12 @@ MemTrie::~MemTrie()
h256 MemTrie::hash256() const
{
return m_root ? m_root->hash256() : eth::sha3(RLPNull);
return m_root ? m_root->hash256() : h256();
}
bytes MemTrie::rlp() const
{
return m_root ? m_root->rlp() : RLPNull;
return m_root ? m_root->rlp() : bytes();
}
void MemTrie::debugPrint()

113
libethereum/RLP.cpp

@ -45,14 +45,6 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
{
auto pl = _parent.payload();
m_lastItem = pl.cropped(0, RLP(pl).actualSize());
uint t = 0;
for (uint i = 0; i < _parent.itemCount(); ++i)
t += _parent[i].actualSize();
if (pl.size() != t)
cout << _parent.itemCount() << " " << asHex(pl);
assert(pl.size() == t);
m_remaining = pl.size() - m_lastItem.size();
}
else
@ -64,15 +56,13 @@ RLP::iterator::iterator(RLP const& _parent, bool _begin)
RLP RLP::operator[](uint _i) const
{
if (!isList() || itemCount() <= _i)
return RLP();
if (_i < m_lastIndex)
{
m_lastEnd = RLP(payload()).actualSize();
m_lastItem = payload().cropped(0, m_lastEnd);
m_lastIndex = 0;
}
for (; m_lastIndex < _i; ++m_lastIndex)
for (; m_lastIndex < _i && m_lastItem.size(); ++m_lastIndex)
{
m_lastItem = payload().cropped(m_lastEnd);
m_lastItem = m_lastItem.cropped(0, RLP(m_lastItem).actualSize());
@ -86,9 +76,8 @@ RLPs RLP::toList() const
RLPs ret;
if (!isList())
return ret;
uint64_t c = items();
for (uint64_t i = 0; i < c; ++i)
ret.push_back(operator[](i));
for (auto const& i: *this)
ret.push_back(i);
return ret;
}
@ -98,15 +87,8 @@ eth::uint RLP::actualSize() const
return 0;
if (isSingleByte())
return 1;
if (isData())
return payload().data() - m_data.data() + items();
if (isList())
{
bytesConstRef d = payload();
uint64_t c = items();
for (uint64_t i = 0; i < c; ++i, d = d.cropped(RLP(d).actualSize())) {}
return d.data() - m_data.data();
}
if (isData() || isList())
return payload().data() - m_data.data() + length();
return 0;
}
@ -115,7 +97,9 @@ bool RLP::isInt() const
byte n = m_data[0];
if (n < c_rlpDataImmLenStart)
return !!n;
else if (n <= c_rlpDataImmLenStart + c_rlpDataImmLenCount)
else if (n == c_rlpDataImmLenStart)
return true;
else if (n <= c_rlpDataIndLenZero)
return m_data[1];
else if (n < c_rlpListStart)
return m_data[1 + n - c_rlpDataIndLenZero];
@ -124,18 +108,18 @@ bool RLP::isInt() const
return false;
}
eth::uint RLP::items() const
eth::uint RLP::length() const
{
uint ret = 0;
byte n = m_data[0];
if (n < c_rlpDataImmLenStart)
return 1;
else if (n <= c_rlpDataImmLenStart + c_rlpDataImmLenCount)
else if (n <= c_rlpDataIndLenZero)
return n - c_rlpDataImmLenStart;
else if (n < c_rlpListStart)
for (int i = 0; i < n - c_rlpDataIndLenZero; ++i)
ret = (ret << 8) | m_data[i + 1];
else if (n <= c_rlpListStart + c_rlpDataImmLenCount)
else if (n <= c_rlpListIndLenZero)
return n - c_rlpListStart;
else
for (int i = 0; i < n - c_rlpListIndLenZero; ++i)
@ -143,20 +127,81 @@ eth::uint RLP::items() const
return ret;
}
RLPStream& RLPStream::appendRaw(bytesConstRef _s)
eth::uint RLP::items() const
{
if (isList())
{
bytesConstRef d = payload().cropped(0, length());
eth::uint i = 0;
for (; d.size(); ++i)
d = d.cropped(RLP(d).actualSize());
return i;
}
return 0;
}
RLPStream& RLPStream::appendRaw(bytesConstRef _s, uint _itemCount)
{
uint os = m_out.size();
m_out.resize(os + _s.size());
memcpy(m_out.data() + os, _s.data(), _s.size());
noteAppended(_itemCount);
return *this;
}
void RLPStream::noteAppended(uint _itemCount)
{
if (!_itemCount)
return;
// cdebug << "noteAppended(" << _itemCount << ")";
while (m_listStack.size())
{
assert(m_listStack.back().first >= _itemCount);
m_listStack.back().first -= _itemCount;
if (m_listStack.back().first)
break;
else
{
auto p = m_listStack.back().second;
m_listStack.pop_back();
uint s = m_out.size() - p; // list size
auto brs = bytesRequired(s);
uint encodeSize = s < c_rlpListImmLenCount ? 1 : (1 + brs);
// cdebug << "s: " << s << ", p: " << p << ", m_out.size(): " << m_out.size() << ", encodeSize: " << encodeSize << " (br: " << brs << ")";
auto os = m_out.size();
m_out.resize(os + encodeSize);
memmove(m_out.data() + p + encodeSize, m_out.data() + p, os - p);
if (s < c_rlpListImmLenCount)
m_out[p] = c_rlpListStart + s;
else
{
m_out[p] = c_rlpListIndLenZero + brs;
byte* b = &(m_out[p + brs]);
for (; s; s >>= 8)
*(b--) = (byte)s;
}
}
_itemCount = 1; // for all following iterations, we've effectively appended a single item only since we completed a list.
}
}
RLPStream& RLPStream::appendList(unsigned _items)
{
// cdebug << "appendList(" << _items << ")";
if (_items)
m_listStack.push_back(std::make_pair(_items, m_out.size()));
else
appendList(bytes());
return *this;
}
RLPStream& RLPStream::appendList(uint _count)
RLPStream& RLPStream::appendList(bytesConstRef _rlp)
{
if (_count < c_rlpListImmLenCount)
m_out.push_back((byte)(_count + c_rlpListStart));
if (_rlp.size() < c_rlpListImmLenCount)
m_out.push_back((byte)(_rlp.size() + c_rlpListStart));
else
pushCount(_count, c_rlpListIndLenZero);
pushCount(_rlp.size(), c_rlpListIndLenZero);
appendRaw(_rlp, 1);
return *this;
}
@ -175,8 +220,9 @@ RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
m_out.push_back((byte)(s + c_rlpDataImmLenStart));
else
pushCount(s, c_rlpDataIndLenZero);
appendRaw(bytesConstRef(d, s));
appendRaw(bytesConstRef(d, s), 0);
}
noteAppended();
return *this;
}
@ -199,6 +245,7 @@ RLPStream& RLPStream::append(bigint _i)
}
pushInt(_i, br);
}
noteAppended();
return *this;
}

50
libethereum/RLP.h

@ -103,8 +103,8 @@ public:
uint itemCountStrict() const { if (!isList()) throw BadCast(); return items(); }
/// @returns the number of bytes in the data, or zero if it isn't data.
uint size() const { return isData() ? items() : 0; }
uint sizeStrict() const { if (!isData()) throw BadCast(); return items(); }
uint size() const { return isData() ? length() : 0; }
uint sizeStrict() const { if (!isData()) throw BadCast(); return length(); }
/// Equality operators; does best-effort conversion and checks for equality.
bool operator==(char const* _s) const { return isData() && toString() == _s; }
@ -166,13 +166,13 @@ public:
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }
/// Converts to bytearray. @returns the empty byte array if not a string.
bytes toBytes() const { if (!isData()) return bytes(); return bytes(payload().data(), payload().data() + items()); }
bytes toBytes() const { if (!isData()) return bytes(); return bytes(payload().data(), payload().data() + length()); }
/// Converts to bytearray. @returns the empty byte array if not a string.
bytesConstRef toBytesConstRef() const { if (!isData()) return bytesConstRef(); return payload().cropped(0, items()); }
bytesConstRef toBytesConstRef() const { if (!isData()) return bytesConstRef(); return payload().cropped(0, length()); }
/// Converts to string. @returns the empty string if not a string.
std::string toString() const { if (!isData()) return std::string(); return payload().cropped(0, items()).toString(); }
std::string toString() const { if (!isData()) return std::string(); return payload().cropped(0, length()).toString(); }
/// Converts to string. @throws BadCast if not a string.
std::string toStringStrict() const { if (!isData()) throw BadCast(); return payload().cropped(0, items()).toString(); }
std::string toStringStrict() const { if (!isData()) throw BadCast(); return payload().cropped(0, length()).toString(); }
template <class T> std::vector<T> toVector() const { std::vector<T> ret; if (isList()) { ret.reserve(itemCount()); for (auto const& i: *this) ret.push_back((T)i); } return ret; }
template <class T, size_t N> std::array<T, N> toArray() const { std::array<T, N> ret; if (itemCount() != N) throw BadCast(); if (isList()) for (uint i = 0; i < N; ++i) ret[i] = (T)operator[](i); return ret; }
@ -210,7 +210,7 @@ public:
template <class _N> _N toHash(int _flags = Strict) const
{
if (!isData() || (items() > _N::size && (_flags & FailIfTooBig)))
if (!isData() || (length() > _N::size && (_flags & FailIfTooBig)))
if (_flags & ThrowOnFail)
throw BadCast();
else
@ -218,7 +218,7 @@ public:
else{}
_N ret;
size_t s = std::min((size_t)_N::size, (size_t)items());
size_t s = std::min((size_t)_N::size, (size_t)length());
memcpy(ret.data() + _N::size - s, payload().data(), s);
return ret;
}
@ -227,11 +227,11 @@ public:
RLPs toList() const;
/// @returns the data payload. Valid for all types.
bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize(), items()); }
bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize()); }
private:
/// Single-byte data payload.
bool isSingleByte() const { assert(!isNull()); return m_data[0] < c_rlpDataImmLenStart; }
bool isSingleByte() const { return !isNull() && m_data[0] < c_rlpDataImmLenStart; }
/// @returns the theoretical size of this item; if it's a list, will require a deep traversal which could take a while.
/// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
@ -240,7 +240,10 @@ private:
/// @returns the bytes used to encode the length of the data. Valid for all types.
uint lengthSize() const { if (isData() && m_data[0] > c_rlpDataIndLenZero) return m_data[0] - c_rlpDataIndLenZero; if (isList() && m_data[0] > c_rlpListIndLenZero) return m_data[0] - c_rlpListIndLenZero; return 0; }
/// @returns the number of data items (bytes in the case of strings & ints, items in the case of lists). Valid for all types.
/// @returns the size in bytes of the payload, as given by the RLP as opposed to as inferred from m_data.
uint length() const;
/// @returns the number of data items.
uint items() const;
/// Our byte data.
@ -264,6 +267,8 @@ public:
/// Initializes the RLPStream as a list of @a _listItems items.
explicit RLPStream(uint _listItems) { appendList(_listItems); }
~RLPStream() {}
/// Append given datum to the byte stream.
RLPStream& append(uint _s) { return append(bigint(_s)); }
RLPStream& append(u160 _s) { return append(bigint(_s)); }
@ -276,33 +281,38 @@ public:
RLPStream& append(h160 _s, bool _compact = false) { return append(_s.ref(), _compact); }
RLPStream& append(h256 _s, bool _compact = false) { return append(_s.ref(), _compact); }
/// Appends an arbitrary RLP fragment.
RLPStream& append(RLP const& _rlp) { return appendRaw(_rlp.data()); }
/// Appends an arbitrary RLP fragment - this *must* be a single item.
RLPStream& append(RLP const& _rlp, uint _itemCount = 1) { return appendRaw(_rlp.data(), _itemCount); }
/// Appends a sequence of data to the stream as a list.
template <class _T> RLPStream& append(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T, size_t S> RLPStream& append(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
/// Appends a list.
RLPStream& appendList(uint _count);
RLPStream& appendList(unsigned _items);
RLPStream& appendList(bytesConstRef _rlp);
RLPStream& appendList(bytes const& _rlp) { return appendList(&_rlp); }
RLPStream& appendList(RLPStream const& _s) { return appendList(&_s.out()); }
/// Appends raw (pre-serialised) RLP data. Use with caution.
RLPStream& appendRaw(bytesConstRef _rlp);
RLPStream& appendRaw(bytes const& _rlp) { return appendRaw(&_rlp); }
RLPStream& appendRaw(bytesConstRef _rlp, uint _itemCount = 1);
RLPStream& appendRaw(bytes const& _rlp, uint _itemCount = 1) { return appendRaw(&_rlp, _itemCount); }
/// Shift operators for appending data items.
template <class T> RLPStream& operator<<(T _data) { return append(_data); }
/// Clear the output stream so far.
void clear() { m_out.clear(); }
void clear() { m_out.clear(); m_listStack.clear(); }
/// Read the byte stream.
bytes const& out() const { return m_out; }
bytes const& out() const { assert(m_listStack.empty()); return m_out; }
/// Swap the contents of the output stream out for some other byte array.
void swapOut(bytes& _dest) { swap(m_out, _dest); }
void swapOut(bytes& _dest) { assert(m_listStack.empty()); swap(m_out, _dest); }
private:
void noteAppended(uint _itemCount = 1);
/// Push the node-type byte (using @a _base) along with the item count @a _count.
/// @arg _count is number of characters for strings, data-bytes for ints, or items for lists.
void pushCount(uint _count, byte _offset);
@ -326,6 +336,8 @@ private:
/// Our output byte stream.
bytes m_out;
std::vector<std::pair<uint, uint>> m_listStack;
};
template <class _T> void rlpListAux(RLPStream& _out, _T _t) { _out << _t; }

9
libethereum/TrieDB.h

@ -182,7 +182,14 @@ public:
m_trail.pop_back();
continue;
}
assert(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17));
if (!(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17)))
{
cdebug << b.rlp.size() << asHex(b.rlp);
cdebug << rlp;
auto c = rlp.itemCount();
cdebug << c;
assert(rlp.isList() && (rlp.itemCount() == 2 || rlp.itemCount() == 17));
}
if (rlp.itemCount() == 2)
{
// Just turn it into a valid Branch

6
libethereum/TrieHash.cpp

@ -159,7 +159,7 @@ h256 hash256(StringMap const& _s)
{
// build patricia tree.
if (_s.empty())
return sha3(RLPNull);
return h256();
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second;
@ -172,7 +172,7 @@ bytes rlp256(StringMap const& _s)
{
// build patricia tree.
if (_s.empty())
return RLPNull;
return bytes();
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(i->first)] = i->second;
@ -185,7 +185,7 @@ h256 hash256(u256Map const& _s)
{
// build patricia tree.
if (_s.empty())
return sha3(RLPNull);
return h256();
HexMap hexMap;
for (auto i = _s.rbegin(); i != _s.rend(); ++i)
hexMap[toHex(toBigEndianString(i->first))] = asString(rlp(i->second));

10
test/main.cpp

@ -35,19 +35,19 @@ using namespace eth;
int main(int argc, char** argv)
{
RLPStream s;
/* RLPStream s;
BlockInfo::genesis().fillStream(s, false);
std::cout << RLP(s.out()) << std::endl;
std::cout << asHex(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;
std::cout << sha3(s.out()) << std::endl;*/
// hexPrefixTest();
// rlpTest();
hexPrefixTest();
rlpTest();
trieTest();
// daggerTest();
// cryptoTest();
// stateTest();
peerTest(argc, argv);
// peerTest(argc, argv);
return 0;
}

6
test/rlp.cpp

@ -35,12 +35,12 @@ int rlpTest()
assert(asString(rlp("dog")) == "\x83""dog");
// 2-item list
string twoItemListString = "\xc2\x0f\x83""dog";
string twoItemListString = "\xc5\x0f\x83""dog";
RLP twoItemList(twoItemListString);
assert(twoItemList.itemCount() == 2);
assert(twoItemList[0] == 15);
assert(twoItemList[1] == "dog");
assert(asString(rlpList(15, "dog")) == "\xc2\x0f\x83""dog");
assert(asString(rlpList(15, "dog")) == "\xc5\x0f\x83""dog");
// null
assert(RLP("\x80") == "");
@ -56,7 +56,7 @@ int rlpTest()
// 32-byte (256-bit) int
assert(RLP("\xa0\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"));
assert(asString(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"))) == "\x37\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");
assert(asString(rlp(bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"))) == "\xa0\x10\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f");
// 56-character string.
assert(RLP("\xb8\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit");

Loading…
Cancel
Save