diff --git a/Common.h b/Common.h index f2daa4520..cc88eb77e 100644 --- a/Common.h +++ b/Common.h @@ -23,4 +23,12 @@ using sint = int64_t; template std::string toString(_T const& _t) { std::ostringstream o; o << _t; return o.str(); } +template inline std::string asHex(_T const& _data) +{ + std::ostringstream ret; + for (auto i: _data) + ret << std::hex << std::setfill('0') << std::setw(2) << (int)i; + return ret.str(); +} + } diff --git a/PatriciaTree.h b/PatriciaTree.h index 16d801b35..bc1e9ba19 100644 --- a/PatriciaTree.h +++ b/PatriciaTree.h @@ -25,7 +25,7 @@ using HexMap = std::map; * [1,2,3,4,T] 0x201234 */ -inline std::string fromHex(bytes const& _hexVector, bool _terminated = false, int _begin = 0, int _end = -1) +inline std::string hexPrefixEncode(bytes const& _hexVector, bool _terminated = false, int _begin = 0, int _end = -1) { uint begin = _begin; uint end = _end < 0 ? _hexVector.size() + 1 + _end : _end; @@ -43,42 +43,73 @@ inline std::string fromHex(bytes const& _hexVector, bool _terminated = false, in return ret; } -inline u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen) +inline bytes toHex(std::string const& _s) { - unsigned c = 0; - for (auto i = _begin; i != _end; ++i, ++c) {} + std::vector ret; + ret.reserve(_s.size() * 2); + for (auto i: _s) + { + ret.push_back(i / 16); + ret.push_back(i % 16); + } + return ret; +} - assert(c > 0); +inline u256 hash256aux(HexMap const& _s, HexMap::const_iterator _begin, HexMap::const_iterator _end, unsigned _preLen) +{ RLPStream rlp; - if (c == 1) + if (_begin == _end) + { + rlp << ""; // NULL + } + else if (std::next(_begin) == _end) { // only one left - terminate with the pair. - rlp << RLPList(2) << fromHex(_begin->first, true, _preLen) << _begin->second; + rlp << RLPList(2) << hexPrefixEncode(_begin->first, true, _preLen) << _begin->second; } else { - // if they all have the same next nibble, we also want a pair. - - // otherwise enumerate all 16+1 entries. - for (auto i = 0; i < 16; ++i) + // find the number of common prefix nibbles shared + // i.e. the minimum number of nibbles shared at the beginning between the first hex string and each successive. + uint sharedPre = (uint)-1; + uint c = 0; + for (auto i = std::next(_begin); i != _end && sharedPre; ++i, ++c) { + uint x = std::min(sharedPre, std::min(_begin->first.size(), i->first.size())); + uint shared = _preLen; + for (; shared < x && _begin->first[shared] == i->first[shared]; ++shared) {} + sharedPre = std::min(shared, sharedPre); + } + if (sharedPre > _preLen) + { + // if they all have the same next nibble, we also want a pair. + rlp << RLPList(2) << hexPrefixEncode(_begin->first, false, _preLen, sharedPre) << hash256aux(_s, _begin, _end, sharedPre); + } + else + { + // otherwise enumerate all 16+1 entries. + rlp << RLPList(17); + auto b = _begin; + if (_preLen == b->first.size()) + ++b; + for (auto i = 0; i < 16; ++i) + { + auto n = b; + for (; n != _end && n->first[_preLen] == i; ++n) {} + if (b == n) + rlp << ""; + else + rlp << hash256aux(_s, b, n, _preLen + 1); + b = n; + } + if (_preLen == _begin->first.size()) + rlp << _begin->second; } } + std::cout << std::hex << sha256(rlp.out()) << ": " << RLP(rlp.out()) << std::endl; return sha256(rlp.out()); } -inline bytes toHex(std::string const& _s) -{ - std::vector ret(_s.size() * 2 + 1); - for (auto i: _s) - { - ret.push_back(i / 16); - ret.push_back(i % 16); - } - ret.push_back(16); - return ret; -} - inline u256 hash256(StringMap const& _s) { // build patricia tree. diff --git a/RLP.h b/RLP.h index 8131a9473..c47b177e1 100644 --- a/RLP.h +++ b/RLP.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "foreign.h" #include "Common.h" @@ -142,6 +143,8 @@ private: uint size() const { + if (isNull()) + return 0; if (isInt()) return 1 + intSize(); if (isString()) @@ -210,12 +213,12 @@ public: pushCount(_count, 0x80); } - RLPStream operator<<(uint _i) { append(_i); return *this; } - RLPStream operator<<(u256 _i) { append(_i); return *this; } - RLPStream operator<<(bigint _i) { append(_i); return *this; } - RLPStream operator<<(char const* _s) { append(std::string(_s)); return *this; } - RLPStream operator<<(std::string const& _s) { append(_s); return *this; } - RLPStream operator<<(RLPList _l) { appendList(_l.count); return *this; } + RLPStream& operator<<(uint _i) { append(_i); return *this; } + RLPStream& operator<<(u256 _i) { append(_i); return *this; } + RLPStream& operator<<(bigint _i) { append(_i); return *this; } + RLPStream& operator<<(char const* _s) { append(std::string(_s)); return *this; } + RLPStream& operator<<(std::string const& _s) { append(_s); return *this; } + RLPStream& operator<<(RLPList _l) { appendList(_l.count); return *this; } bytes const& out() const { return m_out; } std::string str() const { return std::string((char const*)m_out.data(), (char const*)(m_out.data() + m_out.size())); } @@ -292,14 +295,36 @@ private: } +inline std::string escaped(std::string const& _s) +{ + std::string ret; + ret.reserve(_s.size()); + ret.push_back('"'); + for (auto i: _s) + if (i == '"') + ret += "\\\""; + else if (i == '\\') + ret += "\\\\"; + else if (i < ' ' || i > 127) + { + ret += "\\x"; + ret.push_back("0123456789abcdef"[i / 16]); + ret.push_back("0123456789abcdef"[i % 16]); + } + else + ret.push_back(i); + ret.push_back('"'); + return ret; +} + inline std::ostream& operator<<(std::ostream& _out, eth::RLP _d) { if (_d.isNull()) _out << "null"; else if (_d.isInt()) - _out << _d.toBigInt(); + _out << std::showbase << std::hex << std::nouppercase << _d.toBigInt(); else if (_d.isString()) - _out << "\"" << _d.toString() << "\""; + _out << escaped(_d.toString()); else if (_d.isList()) { _out << "["; diff --git a/main.cpp b/main.cpp index 0a81c3b73..226722034 100644 --- a/main.cpp +++ b/main.cpp @@ -1,25 +1,10 @@ +#include "Common.h" #include "RLP.h" #include "PatriciaTree.h" #include "VirtualMachine.h" using namespace std; using namespace eth; -std::string asHex(std::string const& _data) -{ - std::ostringstream ret; - for (auto i: _data) - ret << hex << setfill('0') << setw(2) << (int)i; - return ret.str(); -} - -std::string asHex(bytes const& _data) -{ - std::ostringstream ret; - for (auto i: _data) - ret << hex << setfill('0') << setw(2) << (int)i; - return ret.str(); -} - template void rlpListAux(RLPStream& _out, _T _t) { _out << _t; @@ -48,6 +33,11 @@ template std::string rlpList(_Ts ... _ts) int main() { + cout << hex << hash256({{"dog", "puppy"}}) << endl; + cout << hex << hash256({{"dog", "puppy"}, {"horse", "stallion"}}) << endl; + cout << hex << hash256({{"dog", "puppy"}, {"doge", "coin"}}) << endl; + cout << hex << hash256({{"dog", "puppy"}, {"horse", "stallion"}, {"do", "verb"}, {"doge", "coin"}}) << endl; + // int of value 15 assert(RLP("\x0f") == 15); assert(rlp(15) == "\x0f"); @@ -95,17 +85,17 @@ int main() * [1,2,3,4,5,T] 0x312345 * [1,2,3,4,T] 0x201234 */ - assert(asHex(fromHex({0, 0, 1, 2, 3, 4, 5}, false)) == "10012345"); - assert(asHex(fromHex({0, 1, 2, 3, 4, 5}, false)) == "00012345"); - assert(asHex(fromHex({1, 2, 3, 4, 5}, false)) == "112345"); - assert(asHex(fromHex({0, 0, 1, 2, 3, 4}, false)) == "00001234"); - assert(asHex(fromHex({0, 1, 2, 3, 4}, false)) == "101234"); - assert(asHex(fromHex({1, 2, 3, 4}, false)) == "001234"); - assert(asHex(fromHex({0, 0, 1, 2, 3, 4, 5}, true)) == "30012345"); - assert(asHex(fromHex({0, 0, 1, 2, 3, 4}, true)) == "20001234"); - assert(asHex(fromHex({0, 1, 2, 3, 4, 5}, true)) == "20012345"); - assert(asHex(fromHex({1, 2, 3, 4, 5}, true)) == "312345"); - assert(asHex(fromHex({1, 2, 3, 4}, true)) == "201234"); + assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, false)) == "10012345"); + assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, false)) == "00012345"); + assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, false)) == "112345"); + assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, false)) == "00001234"); + assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4}, false)) == "101234"); + assert(asHex(hexPrefixEncode({1, 2, 3, 4}, false)) == "001234"); + assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4, 5}, true)) == "30012345"); + assert(asHex(hexPrefixEncode({0, 0, 1, 2, 3, 4}, true)) == "20001234"); + assert(asHex(hexPrefixEncode({0, 1, 2, 3, 4, 5}, true)) == "20012345"); + assert(asHex(hexPrefixEncode({1, 2, 3, 4, 5}, true)) == "312345"); + assert(asHex(hexPrefixEncode({1, 2, 3, 4}, true)) == "201234"); return 0; }