Browse Source

First effort at new RLP. **UNTESTED**

cl-refactor
Gav Wood 11 years ago
parent
commit
a70f350b28
  1. 3
      libethereum/BlockInfo.cpp
  2. 3
      libethereum/Common.h
  3. 2
      libethereum/MemTrie.cpp
  4. 123
      libethereum/RLP.cpp
  5. 195
      libethereum/RLP.h
  6. 10
      libethereum/Transaction.cpp
  7. 26
      libethereum/TrieDB.h
  8. 2
      libethereum/TrieHash.cpp
  9. 30
      test/rlp.cpp

3
libethereum/BlockInfo.cpp

@ -71,8 +71,7 @@ h256 BlockInfo::headerHashWithoutNonce() const
void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const void BlockInfo::fillStream(RLPStream& _s, bool _nonce) const
{ {
_s.appendList(_nonce ? 9 : 8) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << sha3Transactions << difficulty << timestamp; _s.appendList(_nonce ? 9 : 8) << parentHash << sha3Uncles << coinbaseAddress << stateRoot << sha3Transactions << difficulty << timestamp << extraData;
_s.appendString(extraData);
if (_nonce) if (_nonce)
_s << nonce; _s << nonce;
} }

3
libethereum/Common.h

@ -96,6 +96,9 @@ public:
byte& operator[](unsigned _i) { return m_data[_i]; } byte& operator[](unsigned _i) { return m_data[_i]; }
byte operator[](unsigned _i) const { return m_data[_i]; } byte operator[](unsigned _i) const { return m_data[_i]; }
bytesRef ref() { return bytesRef(m_data.data(), N); }
bytesConstRef ref() const { return bytesConstRef(m_data.data(), N); }
byte* data() { return m_data.data(); } byte* data() { return m_data.data(); }
byte const* data() const { return m_data.data(); } byte const* data() const { return m_data.data(); }

2
libethereum/MemTrie.cpp

@ -31,7 +31,7 @@ namespace eth
#define ENABLE_DEBUG_PRINT 0 #define ENABLE_DEBUG_PRINT 0
/*/ /*/
#define APPEND_CHILD appendString #define APPEND_CHILD appendData
/*/ /*/
#define APPEND_CHILD appendRaw #define APPEND_CHILD appendRaw
/**/ /**/

123
libethereum/RLP.cpp

@ -96,9 +96,9 @@ eth::uint RLP::actualSize() const
{ {
if (isNull()) if (isNull())
return 0; return 0;
if (isInt()) if (isSingleByte())
return 1 + intSize(); return 1;
if (isString()) if (isData())
return payload().data() - m_data.data() + items(); return payload().data() - m_data.data() + items();
if (isList()) if (isList())
{ {
@ -110,39 +110,37 @@ eth::uint RLP::actualSize() const
return 0; return 0;
} }
eth::uint RLP::items() const bool RLP::isInt() const
{
auto n = (m_data[0] & 0x3f);
if (n < 0x38)
return n;
uint ret = 0;
for (int i = 0; i < n - 0x37; ++i)
ret = (ret << 8) | m_data[i + 1];
return ret;
}
RLPStream& RLPStream::appendString(bytesConstRef _s)
{ {
if (_s.size() < 0x38) byte n = m_data[0];
m_out.push_back((byte)(_s.size() | 0x40)); if (n < c_rlpDataImmLenStart)
return !!n;
else if (n <= c_rlpDataImmLenStart + c_rlpDataImmLenCount)
return m_data[1];
else if (n < c_rlpListStart)
return m_data[1 + n - c_rlpDataIndLenZero];
else else
pushCount(_s.size(), 0x40); return false;
uint os = m_out.size(); return false;
m_out.resize(os + _s.size());
memcpy(m_out.data() + os, _s.data(), _s.size());
return *this;
} }
RLPStream& RLPStream::appendString(string const& _s) eth::uint RLP::items() const
{ {
if (_s.size() < 0x38) uint ret = 0;
m_out.push_back((byte)(_s.size() | 0x40)); byte n = m_data[0];
if (n < c_rlpDataImmLenStart)
return 1;
else if (n <= c_rlpDataImmLenStart + c_rlpDataImmLenCount)
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)
return n - c_rlpListStart;
else else
pushCount(_s.size(), 0x40); for (int i = 0; i < n - c_rlpListIndLenZero; ++i)
uint os = m_out.size(); ret = (ret << 8) | m_data[i + 1];
m_out.resize(os + _s.size()); return ret;
memcpy(m_out.data() + os, _s.data(), _s.size());
return *this;
} }
RLPStream& RLPStream::appendRaw(bytesConstRef _s) RLPStream& RLPStream::appendRaw(bytesConstRef _s)
@ -155,65 +153,48 @@ RLPStream& RLPStream::appendRaw(bytesConstRef _s)
RLPStream& RLPStream::appendList(uint _count) RLPStream& RLPStream::appendList(uint _count)
{ {
if (_count < 0x38) if (_count < c_rlpListImmLenCount)
m_out.push_back((byte)(_count | 0x80)); m_out.push_back((byte)(_count + c_rlpListStart));
else else
pushCount(_count, 0x80); pushCount(_count, c_rlpListIndLenZero);
return *this; return *this;
} }
RLPStream& RLPStream::append(uint _i) RLPStream& RLPStream::append(bytesConstRef _s, bool _compact)
{ {
if (_i < 0x18) uint s = _s.size();
m_out.push_back((byte)_i); byte const* d = _s.data();
else if (_compact)
{ for (unsigned i = 0; i < _s.size() && !*d; ++i, --s, ++d) {}
auto br = bytesRequired(_i);
m_out.push_back((byte)(br + 0x17)); // max 8 bytes.
pushInt(_i, br);
}
return *this;
}
RLPStream& RLPStream::append(u160 _i)
{
if (_i < 0x18)
m_out.push_back((byte)_i);
else
{
auto br = bytesRequired(_i);
m_out.push_back((byte)(br + 0x17)); // max 8 bytes.
pushInt(_i, br);
}
return *this;
}
RLPStream& RLPStream::append(u256 _i) if (s == 1 && *d < c_rlpDataImmLenStart)
{ m_out.push_back(*d);
if (_i < 0x18)
m_out.push_back((byte)_i);
else else
{ {
auto br = bytesRequired(_i); if (s < c_rlpDataImmLenCount)
m_out.push_back((byte)(br + 0x17)); // max 8 bytes. m_out.push_back((byte)(s + c_rlpDataImmLenStart));
pushInt(_i, br); else
pushCount(s, c_rlpDataIndLenZero);
appendRaw(bytesConstRef(d, s));
} }
return *this; return *this;
} }
RLPStream& RLPStream::append(bigint _i) RLPStream& RLPStream::append(bigint _i)
{ {
if (_i < 0x18) if (!_i)
m_out.push_back(c_rlpDataImmLenStart);
else if (_i < c_rlpDataImmLenStart)
m_out.push_back((byte)_i); m_out.push_back((byte)_i);
else else
{ {
uint br = bytesRequired(_i); uint br = bytesRequired(_i);
if (br <= 32) if (br < c_rlpDataImmLenCount)
m_out.push_back((byte)(bytesRequired(_i) + 0x17)); // max 32 bytes. m_out.push_back((byte)(br + c_rlpDataImmLenStart));
else else
{ {
auto brbr = bytesRequired(br); auto brbr = bytesRequired(br);
m_out.push_back((byte)(0x37 + brbr)); m_out.push_back((byte)(c_rlpDataIndLenZero + brbr));
pushInt(br, brbr); pushInt(br, brbr);
} }
pushInt(_i, br); pushInt(_i, br);
@ -224,7 +205,7 @@ RLPStream& RLPStream::append(bigint _i)
void RLPStream::pushCount(uint _count, byte _base) void RLPStream::pushCount(uint _count, byte _base)
{ {
auto br = bytesRequired(_count); auto br = bytesRequired(_count);
m_out.push_back((byte)(br + 0x37 + _base)); // max 8 bytes. m_out.push_back((byte)(br + _base)); // max 8 bytes.
pushInt(_count, br); pushInt(_count, br);
} }
@ -233,8 +214,8 @@ std::ostream& eth::operator<<(std::ostream& _out, eth::RLP const& _d)
if (_d.isNull()) if (_d.isNull())
_out << "null"; _out << "null";
else if (_d.isInt()) else if (_d.isInt())
_out << std::showbase << std::hex << std::nouppercase << _d.toBigInt(RLP::LaisezFaire) << dec; _out << std::showbase << std::hex << std::nouppercase << _d.toInt<bigint>(RLP::LaisezFaire) << dec;
else if (_d.isString()) else if (_d.isData())
_out << eth::escaped(_d.toString(), false); _out << eth::escaped(_d.toString(), false);
else if (_d.isList()) else if (_d.isList())
{ {

195
libethereum/RLP.h

@ -42,6 +42,15 @@ template <> struct intTraits<u160> { static const uint maxSize = 20; };
template <> struct intTraits<u256> { static const uint maxSize = 32; }; template <> struct intTraits<u256> { static const uint maxSize = 32; };
template <> struct intTraits<bigint> { static const uint maxSize = ~(uint)0; }; template <> struct intTraits<bigint> { static const uint maxSize = ~(uint)0; };
static const byte c_rlpMaxLengthBytes = 8;
static const byte c_rlpDataImmLenStart = 0x80;
static const byte c_rlpListStart = 0xc0;
static const byte c_rlpDataImmLenCount = c_rlpListStart - c_rlpDataImmLenStart - c_rlpMaxLengthBytes;
static const byte c_rlpDataIndLenZero = c_rlpDataImmLenStart + c_rlpDataImmLenCount - 1;
static const byte c_rlpListImmLenCount = 256 - c_rlpListStart - c_rlpMaxLengthBytes;
static const byte c_rlpListIndLenZero = c_rlpListStart + c_rlpListImmLenCount - 1;
/** /**
* @brief Class for interpreting Recursive Linear-Prefix Data. * @brief Class for interpreting Recursive Linear-Prefix Data.
* @by Gav Wood, 2013 * @by Gav Wood, 2013
@ -68,6 +77,7 @@ public:
/// Construct a node to read RLP data in the string. /// Construct a node to read RLP data in the string.
explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {} explicit RLP(std::string const& _s): m_data(bytesConstRef((byte const*)_s.data(), _s.size())) {}
/// The bare data of the RLP.
bytesConstRef data() const { return m_data; } bytesConstRef data() const { return m_data; }
/// @returns true if the RLP is non-null. /// @returns true if the RLP is non-null.
@ -77,49 +87,38 @@ public:
bool isNull() const { return m_data.size() == 0; } bool isNull() const { return m_data.size() == 0; }
/// Contains a zero-length string or zero-length list. /// Contains a zero-length string or zero-length list.
bool isEmpty() const { return !isNull() && (m_data[0] == 0x40 || m_data[0] == 0x80); } bool isEmpty() const { return !isNull() && (m_data[0] == c_rlpDataImmLenStart || m_data[0] == c_rlpListStart); }
/// String value. /// String value.
bool isString() const { return !isNull() && m_data[0] >= 0x40 && m_data[0] < 0x80; } bool isData() const { return !isNull() && m_data[0] < c_rlpListStart; }
/// List value. /// List value.
bool isList() const { return !isNull() && m_data[0] >= 0x80 && m_data[0] < 0xc0; } bool isList() const { return !isNull() && m_data[0] >= c_rlpListStart; }
/// Integer value. Either isSlimInt(), isFatInt() or isBigInt().
bool isInt() const { return !isNull() && m_data[0] < 0x40; }
/// Fits into eth::uint type. Can use toSlimInt() to read (as well as toFatInt() or toBigInt() ).
bool isSlimInt() const { return !isNull() && m_data[0] < 0x20; }
/// Fits into eth::u256 or eth::bigint type. Use only toFatInt() or toBigInt() to read.
bool isFatInt() const { return !isNull() && m_data[0] >= 0x20 && m_data[0] < 0x38; }
/// Fits into eth::u256 type, though might fit into eth::uint type.
bool isFixedInt() const { return !isNull() && m_data[0] < 0x38; }
/// Fits only into eth::bigint type. Use only toBigInt() to read. /// Integer value. Must not have a leading zero.
bool isBigInt() const { return !isNull() && m_data[0] >= 0x38 && m_data[0] < 0x40; } bool isInt() const;
/// @returns the number of items in the list, or zero if it isn't a list. /// @returns the number of items in the list, or zero if it isn't a list.
uint itemCount() const { return isList() ? items() : 0; } uint itemCount() const { return isList() ? items() : 0; }
uint itemCountStrict() const { if (!isList()) throw BadCast(); return items(); } uint itemCountStrict() const { if (!isList()) throw BadCast(); return items(); }
/// @returns the number of characters in the string, or zero if it isn't a string. /// @returns the number of bytes in the data, or zero if it isn't data.
uint stringSize() const { return isString() ? items() : 0; } uint size() const { return isData() ? items() : 0; }
uint sizeStrict() const { if (!isData()) throw BadCast(); return items(); }
/// Equality operators; does best-effort conversion and checks for equality. /// Equality operators; does best-effort conversion and checks for equality.
bool operator==(char const* _s) const { return isString() && toString() == _s; } bool operator==(char const* _s) const { return isData() && toString() == _s; }
bool operator!=(char const* _s) const { return isString() && toString() != _s; } bool operator!=(char const* _s) const { return isData() && toString() != _s; }
bool operator==(std::string const& _s) const { return isString() && toString() == _s; } bool operator==(std::string const& _s) const { return isData() && toString() == _s; }
bool operator!=(std::string const& _s) const { return isString() && toString() != _s; } bool operator!=(std::string const& _s) const { return isData() && toString() != _s; }
template <unsigned _N> bool operator==(FixedHash<_N> const& _h) const { return isString() && toHash<_N>() == _h; } template <unsigned _N> bool operator==(FixedHash<_N> const& _h) const { return isData() && toHash<_N>() == _h; }
template <unsigned _N> bool operator!=(FixedHash<_N> const& _s) const { return isString() && toHash<_N>() != _s; } template <unsigned _N> bool operator!=(FixedHash<_N> const& _s) const { return isData() && toHash<_N>() != _s; }
bool operator==(uint const& _i) const { return (isInt() || isString()) && toSlimInt() == _i; } bool operator==(uint const& _i) const { return isInt() && toInt<uint>() == _i; }
bool operator!=(uint const& _i) const { return (isInt() || isString()) && toSlimInt() != _i; } bool operator!=(uint const& _i) const { return isInt() && toInt<uint>() != _i; }
bool operator==(u256 const& _i) const { return (isInt() || isString()) && toFatInt() == _i; } bool operator==(u256 const& _i) const { return isInt() && toInt<u256>() == _i; }
bool operator!=(u256 const& _i) const { return (isInt() || isString()) && toFatInt() != _i; } bool operator!=(u256 const& _i) const { return isInt() && toInt<u256>() != _i; }
bool operator==(bigint const& _i) const { return (isInt() || isString()) && toBigInt() == _i; } bool operator==(bigint const& _i) const { return isInt() && toInt<bigint>() == _i; }
bool operator!=(bigint const& _i) const { return (isInt() || isString()) && toBigInt() != _i; } bool operator!=(bigint const& _i) const { return isInt() && toInt<bigint>() != _i; }
/// Subscript operator. /// Subscript operator.
/// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise. /// @returns the list item @a _i if isList() and @a _i < listItems(), or RLP() otherwise.
@ -167,13 +166,13 @@ public:
template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); } template <unsigned _N> explicit operator FixedHash<_N>() const { return toHash<FixedHash<_N>>(); }
/// Converts to bytearray. @returns the empty byte array if not a string. /// Converts to bytearray. @returns the empty byte array if not a string.
bytes toBytes() const { if (!isString()) return bytes(); return bytes(payload().data(), payload().data() + items()); } bytes toBytes() const { if (!isData()) return bytes(); return bytes(payload().data(), payload().data() + items()); }
/// Converts to bytearray. @returns the empty byte array if not a string. /// Converts to bytearray. @returns the empty byte array if not a string.
bytesConstRef toBytesConstRef() const { if (!isString()) return bytesConstRef(); return payload().cropped(0, items()); } bytesConstRef toBytesConstRef() const { if (!isData()) return bytesConstRef(); return payload().cropped(0, items()); }
/// Converts to string. @returns the empty string if not a string. /// Converts to string. @returns the empty string if not a string.
std::string toString() const { if (!isString()) return std::string(); return payload().cropped(0, items()).toString(); } std::string toString() const { if (!isData()) return std::string(); return payload().cropped(0, items()).toString(); }
/// Converts to string. @throws BadCast if not a string. /// Converts to string. @throws BadCast if not a string.
std::string toStringStrict() const { if (!isString()) throw BadCast(); return payload().cropped(0, items()).toString(); } std::string toStringStrict() const { if (!isData()) throw BadCast(); return payload().cropped(0, items()).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> 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; } 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; }
@ -181,47 +180,37 @@ public:
/// Int conversion flags /// Int conversion flags
enum enum
{ {
AllowString = 1, AllowNonCanon = 1,
AllowInt = 2,
ThrowOnFail = 4, ThrowOnFail = 4,
FailIfTooBig = 8, FailIfTooBig = 8,
Strict = AllowString | AllowInt | ThrowOnFail | FailIfTooBig, Strict = ThrowOnFail | FailIfTooBig,
StrictlyString = AllowString | ThrowOnFail | FailIfTooBig, LaisezFaire = AllowNonCanon
StrictlyInt = AllowInt | ThrowOnFail | FailIfTooBig,
LaisezFaire = AllowString | AllowInt
}; };
/// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string. /// Converts to int of type given; if isString(), decodes as big-endian bytestream. @returns 0 if not an int or string.
template <class _T = uint> _T toInt(int _flags = Strict) const template <class _T = uint> _T toInt(int _flags = Strict) const
{ {
if ((isString() && !(_flags & AllowString)) || (isInt() && !(_flags & AllowInt)) || isList() || isNull()) if ((!isInt() && !(_flags & AllowNonCanon)) || isList() || isNull())
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
throw BadCast(); throw BadCast();
else else
return 0; return 0;
else {} else {}
if (isDirectValueInt()) auto p = payload();
return m_data[0]; if (p.size() > intTraits<_T>::maxSize && (_flags & FailIfTooBig))
auto s = isInt() ? intSize() - lengthSize() : isString() ? items() : 0;
if (s > intTraits<_T>::maxSize && (_flags & FailIfTooBig))
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
throw BadCast(); throw BadCast();
else else
return 0; return 0;
else {} else {}
_T ret = 0; return fromBigEndian<_T>(p);
uint o = lengthSize() + 1;
for (uint i = 0; i < s; ++i)
ret = (ret << 8) | m_data[i + o];
return ret;
} }
template <class _N> _N toHash(int _flags = Strict) const template <class _N> _N toHash(int _flags = Strict) const
{ {
if (!isString() || (items() > _N::size && (_flags & FailIfTooBig))) if (!isData() || (items() > _N::size && (_flags & FailIfTooBig)))
if (_flags & ThrowOnFail) if (_flags & ThrowOnFail)
throw BadCast(); throw BadCast();
else else
@ -234,46 +223,22 @@ public:
return ret; return ret;
} }
/// Converts to eth::uint. @see toInt()
uint toSlimInt(int _flags = Strict) const { return toInt<uint>(_flags); }
/// Converts to eth::u256. @see toInt()
u256 toFatInt(int _flags = Strict) const { return toInt<u256>(_flags); }
/// Converts to eth::bigint. @see toInt()
bigint toBigInt(int _flags = Strict) const { return toInt<bigint>(_flags); }
/// Converts to RLPs collection object. Useful if you need random access to sub items or will iterate over multiple times. /// Converts to RLPs collection object. Useful if you need random access to sub items or will iterate over multiple times.
RLPs toList() const; RLPs toList() const;
/// @returns the data payload. Valid for all types. /// @returns the data payload. Valid for all types.
bytesConstRef payload() const { auto n = (m_data[0] & 0x3f); return m_data.cropped(1 + (n < 0x38 ? 0 : (n - 0x37))); } bytesConstRef payload() const { return isSingleByte() ? m_data.cropped(0, 1) : m_data.cropped(1 + lengthSize(), items()); }
private: private:
/// Direct value integer. /// Single-byte data payload.
bool isDirectValueInt() const { assert(!isNull()); return m_data[0] < 0x18; } bool isSingleByte() const { assert(!isNull()); return m_data[0] < c_rlpDataImmLenStart; }
/// Indirect-value integer.
bool isIndirectValueInt() const { assert(!isNull()); return m_data[0] >= 0x18 && m_data[0] < 0x38; }
/// Indirect addressed integer.
bool isIndirectAddressedInt() const { assert(!isNull()); return m_data[0] < 0x40 && m_data[0] >= 0x38; }
/// Direct-length string.
bool isSmallString() const { assert(!isNull()); return m_data[0] >= 0x40 && m_data[0] < 0x78; }
/// Direct-length list.
bool isSmallList() const { assert(!isNull()); return m_data[0] >= 0x80 && m_data[0] < 0xb8; }
/// @returns the theoretical size of this item; if it's a list, will require a deep traversal which could take a while. /// @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. /// @note Under normal circumstances, is equivalent to m_data.size() - use that unless you know it won't work.
uint actualSize() const; uint actualSize() const;
/// @returns the total additional bytes used to encode the integer. Includes the data-size and potentially the length-size. Returns 0 if not isInt().
uint intSize() const { return (!isInt() || isDirectValueInt()) ? 0 : isIndirectAddressedInt() ? lengthSize() + items() : (m_data[0] - 0x17); }
/// @returns the bytes used to encode the length of the data. Valid for all types. /// @returns the bytes used to encode the length of the data. Valid for all types.
uint lengthSize() const { auto n = (m_data[0] & 0x3f); return n > 0x37 ? n - 0x37 : 0; } 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 number of data items (bytes in the case of strings & ints, items in the case of lists). Valid for all types.
uint items() const; uint items() const;
@ -299,45 +264,48 @@ public:
/// Initializes the RLPStream as a list of @a _listItems items. /// Initializes the RLPStream as a list of @a _listItems items.
explicit RLPStream(uint _listItems) { appendList(_listItems); } explicit RLPStream(uint _listItems) { appendList(_listItems); }
/// Append given data to the byte stream. /// Append given datum to the byte stream.
RLPStream& append(uint _s); RLPStream& append(uint _s) { return append(bigint(_s)); }
RLPStream& append(u160 _s); RLPStream& append(u160 _s) { return append(bigint(_s)); }
RLPStream& append(u256 _s); RLPStream& append(u256 _s) { return append(bigint(_s)); }
RLPStream& append(h160 _s, bool _compact = true) { return appendFixed(_s, _compact); }
RLPStream& append(h256 _s, bool _compact = true) { return appendFixed(_s, _compact); }
RLPStream& append(bigint _s); RLPStream& append(bigint _s);
RLPStream& append(bytesConstRef _s, bool _compact = false);
RLPStream& append(bytes const& _s) { return append(bytesConstRef(&_s)); }
RLPStream& append(std::string const& _s) { return append(bytesConstRef(_s)); }
RLPStream& append(char const* _s) { return append(std::string(_s)); }
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 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(uint _count);
RLPStream& appendString(bytesConstRef _s);
RLPStream& appendString(bytes const& _s) { return appendString(bytesConstRef(&_s)); } /// Appends raw (pre-serialised) RLP data. Use with caution.
RLPStream& appendString(std::string const& _s);
RLPStream& appendRaw(bytesConstRef _rlp); RLPStream& appendRaw(bytesConstRef _rlp);
RLPStream& appendRaw(bytes const& _rlp) { return appendRaw(&_rlp); } RLPStream& appendRaw(bytes const& _rlp) { return appendRaw(&_rlp); }
RLPStream& appendRaw(RLP const& _rlp) { return appendRaw(_rlp.data()); }
/// Shift operators for appending data items. /// Shift operators for appending data items.
RLPStream& operator<<(uint _i) { return append(_i); } template <class T> RLPStream& operator<<(T _data) { return append(_data); }
RLPStream& operator<<(u160 _i) { return append(_i); }
RLPStream& operator<<(u256 _i) { return append(_i); }
RLPStream& operator<<(h160 _i) { return append(_i); }
RLPStream& operator<<(h256 _i) { return append(_i); }
RLPStream& operator<<(bigint _i) { return append(_i); }
RLPStream& operator<<(char const* _s) { return appendString(std::string(_s)); }
RLPStream& operator<<(std::string const& _s) { return appendString(_s); }
RLPStream& operator<<(RLP const& _i) { return appendRaw(_i); }
template <class _T> RLPStream& operator<<(std::vector<_T> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
template <class _T, size_t S> RLPStream& operator<<(std::array<_T, S> const& _s) { appendList(_s.size()); for (auto const& i: _s) append(i); return *this; }
/// Clear the output stream so far.
void clear() { m_out.clear(); } void clear() { m_out.clear(); }
/// Read the byte stream. /// Read the byte stream.
bytes const& out() const { return m_out; } bytes const& out() const { 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) { swap(m_out, _dest); }
private: private:
/// Push the node-type byte (using @a _base) along with the item count @a _count. /// 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. /// @arg _count is number of characters for strings, data-bytes for ints, or items for lists.
void pushCount(uint _count, byte _base); void pushCount(uint _count, byte _offset);
/// Push an integer as a raw big-endian byte-stream. /// Push an integer as a raw big-endian byte-stream.
template <class _T> void pushInt(_T _i, uint _br) template <class _T> void pushInt(_T _i, uint _br)
@ -348,29 +316,10 @@ private:
*(b--) = (byte)_i; *(b--) = (byte)_i;
} }
template <unsigned _N>
RLPStream& appendFixed(FixedHash<_N> const& _s, bool _compact)
{
uint s = _N;
byte const* d = _s.data();
if (_compact)
for (unsigned i = 0; i < _N && !*d; ++i, --s, ++d) {}
if (s < 0x38)
m_out.push_back((byte)(s | 0x40));
else
pushCount(s, 0x40);
uint os = m_out.size();
m_out.resize(os + s);
memcpy(m_out.data() + os, d, s);
return *this;
}
/// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero. /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
template <class _T> static uint bytesRequired(_T _i) template <class _T> static uint bytesRequired(_T _i)
{ {
_i >>= 8; uint i = 0;
uint i = 1;
for (; _i != 0; ++i, _i >>= 8) {} for (; _i != 0; ++i, _i >>= 8) {}
return i; return i;
} }

10
libethereum/Transaction.cpp

@ -29,14 +29,14 @@ using namespace eth;
Transaction::Transaction(bytesConstRef _rlpData) Transaction::Transaction(bytesConstRef _rlpData)
{ {
RLP rlp(_rlpData); RLP rlp(_rlpData);
nonce = rlp[0].toInt<u256>(RLP::StrictlyInt); nonce = rlp[0].toInt<u256>();
receiveAddress = rlp[1].toHash<Address>(); receiveAddress = rlp[1].toHash<Address>();
value = rlp[2].toInt<u256>(RLP::StrictlyInt); value = rlp[2].toInt<u256>();
fee = rlp[3].toInt<u256>(RLP::StrictlyInt); fee = rlp[3].toInt<u256>();
data.reserve(rlp[4].itemCountStrict()); data.reserve(rlp[4].itemCountStrict());
for (auto const& i: rlp[4]) for (auto const& i: rlp[4])
data.push_back(i.toInt<u256>(RLP::StrictlyInt)); data.push_back(i.toInt<u256>());
vrs = Signature{ rlp[5].toInt<byte>(RLP::StrictlyInt), rlp[6].toInt<u256>(RLP::StrictlyInt), rlp[7].toInt<u256>(RLP::StrictlyInt) }; vrs = Signature{ rlp[5].toInt<byte>(), rlp[6].toInt<u256>(), rlp[7].toInt<u256>() };
} }
Address Transaction::sender() const Address Transaction::sender() const

26
libethereum/TrieDB.h

@ -477,7 +477,7 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
{ {
killNode(sha3(_orig.data())); killNode(sha3(_orig.data()));
RLPStream s(2); RLPStream s(2);
s.appendRaw(_orig[0]); s.append(_orig[0]);
mergeAtAux(s, _orig[1], _k.mid(k.size()), _v); mergeAtAux(s, _orig[1], _k.mid(k.size()), _v);
return s.out(); return s.out();
} }
@ -509,7 +509,7 @@ template <class DB> bytes GenericTrieDB<DB>::mergeAt(RLP const& _orig, NibbleSli
if (i == n) if (i == n)
mergeAtAux(r, _orig[i], _k.mid(1), _v); mergeAtAux(r, _orig[i], _k.mid(1), _v);
else else
r.appendRaw(_orig[i]); r.append(_orig[i]);
return r.out(); return r.out();
} }
@ -547,7 +547,7 @@ template <class DB> void GenericTrieDB<DB>::remove(bytesConstRef _key)
template <class DB> bool GenericTrieDB<DB>::isTwoItemNode(RLP const& _n) const template <class DB> bool GenericTrieDB<DB>::isTwoItemNode(RLP const& _n) const
{ {
return (_n.isString() && RLP(node(_n.toHash<h256>())).itemCount() == 2) return (_n.isData() && RLP(node(_n.toHash<h256>())).itemCount() == 2)
|| (_n.isList() && _n.itemCount() == 2); || (_n.isList() && _n.itemCount() == 2);
} }
@ -669,16 +669,16 @@ template <class DB> bytes GenericTrieDB<DB>::place(RLP const& _orig, NibbleSlice
killNode(_orig); killNode(_orig);
if (_orig.isEmpty()) if (_orig.isEmpty())
return RLPStream(2).appendString(hexPrefixEncode(_k, true)).appendString(_s).out(); return (RLPStream(2) << hexPrefixEncode(_k, true) << _s).out();
assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17)); assert(_orig.isList() && (_orig.itemCount() == 2 || _orig.itemCount() == 17));
if (_orig.itemCount() == 2) if (_orig.itemCount() == 2)
return RLPStream(2).appendRaw(_orig[0]).appendString(_s).out(); return (RLPStream(2) << _orig[0] << _s).out();
auto s = RLPStream(17); auto s = RLPStream(17);
for (uint i = 0; i < 16; ++i) for (uint i = 0; i < 16; ++i)
s.appendRaw(_orig[i]); s << _orig[i];
s.appendString(_s); s << _s;
return s.out(); return s.out();
} }
@ -695,8 +695,8 @@ template <class DB> bytes GenericTrieDB<DB>::remove(RLP const& _orig)
return RLPNull; return RLPNull;
RLPStream r(17); RLPStream r(17);
for (uint i = 0; i < 16; ++i) for (uint i = 0; i < 16; ++i)
r.appendRaw(_orig[i]); r << _orig[i];
r.appendString(""); r << "";
return r.out(); return r.out();
} }
@ -719,11 +719,10 @@ template <class DB> bytes GenericTrieDB<DB>::cleve(RLP const& _orig, uint _s)
assert(_s && _s <= k.size()); assert(_s && _s <= k.size());
RLPStream bottom(2); RLPStream bottom(2);
bottom.appendString(hexPrefixEncode(k, isLeaf(_orig), _s)); bottom << hexPrefixEncode(k, isLeaf(_orig), _s) << _orig[1];
bottom.appendRaw(_orig[1]);
RLPStream top(2); RLPStream top(2);
top.appendString(hexPrefixEncode(k, false, 0, _s)); top << hexPrefixEncode(k, false, 0, _s);
streamNode(top, bottom.out()); streamNode(top, bottom.out());
return top.out(); return top.out();
@ -790,8 +789,7 @@ template <class DB> bytes GenericTrieDB<DB>::branch(RLP const& _orig)
if (isLeaf(_orig) || k.size() > 1) if (isLeaf(_orig) || k.size() > 1)
{ {
RLPStream bottom(2); RLPStream bottom(2);
bottom.appendString(hexPrefixEncode(k.mid(1), isLeaf(_orig))); bottom << hexPrefixEncode(k.mid(1), isLeaf(_orig)) << _orig[1];
bottom.appendRaw(_orig[1]);
streamNode(r, bottom.out()); streamNode(r, bottom.out());
} }
else else

2
libethereum/TrieHash.cpp

@ -29,7 +29,7 @@ namespace eth
{ {
/*/ /*/
#define APPEND_CHILD appendString #define APPEND_CHILD appendData
/*/ /*/
#define APPEND_CHILD appendRaw #define APPEND_CHILD appendRaw
/**/ /**/

30
test/rlp.cpp

@ -31,36 +31,36 @@ int rlpTest()
assert(asString(rlp(15)) == "\x0f"); assert(asString(rlp(15)) == "\x0f");
// 3-character string // 3-character string
assert(RLP("\x43""dog") == "dog"); assert(RLP("\x83""dog") == "dog");
assert(asString(rlp("dog")) == "\x43""dog"); assert(asString(rlp("dog")) == "\x83""dog");
// 2-item list // 2-item list
string twoItemListString = "\x82\x0f\x43""dog"; string twoItemListString = "\xc2\x0f\x83""dog";
RLP twoItemList(twoItemListString); RLP twoItemList(twoItemListString);
assert(twoItemList.itemCount() == 2); assert(twoItemList.itemCount() == 2);
assert(twoItemList[0] == 15); assert(twoItemList[0] == 15);
assert(twoItemList[1] == "dog"); assert(twoItemList[1] == "dog");
assert(asString(rlpList(15, "dog")) == "\x82\x0f\x43""dog"); assert(asString(rlpList(15, "dog")) == "\xc2\x0f\x83""dog");
// null
assert(RLP("\x80") == "");
assert(asString(rlp("")) == "\x80");
// 1-byte (8-bit) int // 1-byte (8-bit) int
assert(RLP("\x18\x45") == 69); assert(RLP("\x81\x80") == 128);
assert(asString(rlp(69)) == "\x18\x45"); assert(asString(rlp(128)) == "\x81\x80");
// 2-byte (16-bit) int // 2-byte (16-bit) int
assert(RLP("\x19\x01\x01") == 257); assert(RLP("\x82\x01\x01") == 257);
assert(asString(rlp(257)) == "\x19\x01\x01"); assert(asString(rlp(257)) == "\x82\x01\x01");
// 32-byte (256-bit) int // 32-byte (256-bit) int
assert(RLP("\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") == bigint("0x100102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")); 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"))) == "\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");
// 33-byte (264-bit) int
assert(RLP("\x38\x21\x20\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("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"));
assert(asString(rlp(bigint("0x20100102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"))) == "\x38\x21\x20\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. // 56-character string.
assert(RLP("\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit"); assert(RLP("\xb8\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit") == "Lorem ipsum dolor sit amet, consectetur adipisicing elit");
assert(asString(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit")) == "\x78\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit"); assert(asString(rlp("Lorem ipsum dolor sit amet, consectetur adipisicing elit")) == "\xb8\x38""Lorem ipsum dolor sit amet, consectetur adipisicing elit");
return 0; return 0;
} }

Loading…
Cancel
Save