This commit is contained in:
Eddy Ashton 2020-02-19 09:15:20 +00:00 коммит произвёл GitHub
Родитель 12951f37d3
Коммит 73b090fe6b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 497 добавлений и 458 удалений

Просмотреть файл

@ -39,6 +39,8 @@ namespace eevm
template <typename... Ts> template <typename... Ts>
ByteString encode(Ts&&... ts); ByteString encode(Ts&&... ts);
namespace encode_details
{
void prefix_multiple_length(size_t total_length, ByteString& bs); void prefix_multiple_length(size_t total_length, ByteString& bs);
inline ByteString to_byte_string(const ByteString& bs) inline ByteString to_byte_string(const ByteString& bs)
@ -163,7 +165,9 @@ namespace eevm
total_length_as_bytes.insert( total_length_as_bytes.insert(
total_length_as_bytes.begin(), 0xf7 + length_of_total_length); total_length_as_bytes.begin(), 0xf7 + length_of_total_length);
bs.insert( bs.insert(
bs.begin(), total_length_as_bytes.begin(), total_length_as_bytes.end()); bs.begin(),
total_length_as_bytes.begin(),
total_length_as_bytes.end());
} }
// RLP-encode a single, non-tuple argument. Convert it to a ByteString, // RLP-encode a single, non-tuple argument. Convert it to a ByteString,
@ -200,7 +204,8 @@ namespace eevm
auto length_as_bytes = to_byte_string(length); auto length_as_bytes = to_byte_string(length);
const uint8_t length_of_length = length_as_bytes.size(); const uint8_t length_of_length = length_as_bytes.size();
length_as_bytes.insert(length_as_bytes.begin(), 0xb7 + length_of_length); length_as_bytes.insert(
length_as_bytes.begin(), 0xb7 + length_of_length);
bytes.insert( bytes.insert(
bytes.begin(), length_as_bytes.begin(), length_as_bytes.end()); bytes.begin(), length_as_bytes.begin(), length_as_bytes.end());
return bytes; return bytes;
@ -223,7 +228,9 @@ namespace eevm
auto encode_multiple(const std::tuple<Ts...>& tup) auto encode_multiple(const std::tuple<Ts...>& tup)
{ {
return std::apply( return std::apply(
[](auto&&... entry) { return std::make_tuple(encode(entry)...); }, tup); [](auto&&... entry) { return std::make_tuple(encode(entry)...); },
tup);
}
} }
// Main encode function. Either forwards to encode_single, or calls // Main encode function. Either forwards to encode_single, or calls
@ -234,10 +241,11 @@ namespace eevm
{ {
if constexpr (sizeof...(Ts) == 1 && !is_tuple<std::decay_t<Ts>...>::value) if constexpr (sizeof...(Ts) == 1 && !is_tuple<std::decay_t<Ts>...>::value)
{ {
return encode_single(std::forward<Ts>(ts)...); return encode_details::encode_single(std::forward<Ts>(ts)...);
} }
const auto nested_terms = encode_multiple(std::forward<Ts>(ts)...); const auto nested_terms =
encode_details::encode_multiple(std::forward<Ts>(ts)...);
// Get total length by summing size of each term in tuple // Get total length by summing size of each term in tuple
const auto total_length = std::apply( const auto total_length = std::apply(
@ -252,7 +260,7 @@ namespace eevm
}, },
nested_terms); nested_terms);
prefix_multiple_length(total_length, flattened); encode_details::prefix_multiple_length(total_length, flattened);
return flattened; return flattened;
} }
@ -260,6 +268,13 @@ namespace eevm
// Decoding // Decoding
// //
class decode_error : public std::logic_error
{
using logic_error::logic_error;
};
namespace decode_details
{
enum class Arity enum class Arity
{ {
Single, Single,
@ -273,14 +288,9 @@ namespace eevm
size_t length; size_t length;
}; };
class decode_error : public std::logic_error
{
using logic_error::logic_error;
};
// Forward declaration to allow recursive calls. // Forward declaration to allow recursive calls.
template <typename... Ts> template <typename... Ts>
std::tuple<Ts...> decode(const uint8_t*&, size_t&); std::tuple<Ts...> decode_impl(const uint8_t*&, size_t&);
inline std::pair<Arity, size_t> decode_length( inline std::pair<Arity, size_t> decode_length(
const uint8_t*& data, size_t& size); const uint8_t*& data, size_t& size);
@ -295,9 +305,9 @@ namespace eevm
{ {
if (size > 8) if (size > 8)
{ {
throw decode_error( throw decode_error(fmt::format(
"Trying to decode number: " + std::to_string(size) + "Trying to decode number: {} is too many bytes for uint64_t",
" is too many bytes for uint64_t"); size));
} }
size_t result = 0; size_t result = 0;
@ -349,10 +359,10 @@ namespace eevm
{ {
if (size != N) if (size != N)
{ {
throw decode_error( throw decode_error(fmt::format(
"Trying to decode " + std::to_string(N) + "Trying to decode {} byte array, but given {} bytes to decode",
" byte array, but given " + std::to_string(size) + N,
" bytes to decode"); size));
} }
std::array<uint8_t, N> result; std::array<uint8_t, N> result;
@ -375,7 +385,7 @@ namespace eevm
std::array<T, N> result; std::array<T, N> result;
for (auto i = 0u; i < N; ++i) for (auto i = 0u; i < N; ++i)
{ {
result[i] = std::get<0>(decode<T>(data, size)); result[i] = std::get<0>(decode_impl<T>(data, size));
} }
size = 0u; size = 0u;
@ -394,7 +404,8 @@ namespace eevm
std::vector<T> result; std::vector<T> result;
while (contained_length > 0) while (contained_length > 0)
{ {
result.push_back(std::get<0>(decode<T>(data, contained_length))); result.push_back(
std::get<0>(decode_impl<T>(data, contained_length)));
} }
size = 0u; size = 0u;
@ -472,10 +483,11 @@ namespace eevm
if (size < length_of_length) if (size < length_of_length)
{ {
throw decode_error( throw decode_error(fmt::format(
"Length of next element should be encoded in " + "Length of next element should be encoded in {} bytes, but only "
std::to_string(length_of_length) + " bytes, but only " + "{} remain",
std::to_string(size) + " remain"); length_of_length,
size));
} }
size -= length_of_length; size -= length_of_length;
@ -497,10 +509,11 @@ namespace eevm
if (size < length_of_length) if (size < length_of_length)
{ {
throw decode_error( throw decode_error(fmt::format(
"Length of next list should be encoded in " + "Length of next list should be encoded in {} bytes, but only {} "
std::to_string(length_of_length) + " bytes, but only " + "remain",
std::to_string(size) + " remain"); length_of_length,
size));
} }
size -= length_of_length; size -= length_of_length;
@ -530,15 +543,15 @@ namespace eevm
inline std::tuple<T, Ts...> decode_tuple( inline std::tuple<T, Ts...> decode_tuple(
const uint8_t*& data, size_t& size, std::tuple<T, Ts...>) const uint8_t*& data, size_t& size, std::tuple<T, Ts...>)
{ {
const auto first = decode<T>(data, size); const auto first = decode_impl<T>(data, size);
return std::tuple_cat( return std::tuple_cat(
first, decode_tuple<Ts...>(data, size, std::tuple<Ts...>{})); first, decode_tuple<Ts...>(data, size, std::tuple<Ts...>{}));
} }
// Type helper for decoding single item, forwarding to either decode_tuple // Type helper for decoding single item, forwarding to either decode_tuple
// (to unwrap the types contained in a tuple) or directly to the main // (to unwrap the types contained in a tuple) or directly to the top-level
// decode function // decode_impl function
template <typename T> template <typename T>
auto decode_item(const uint8_t*& data, size_t& size) auto decode_item(const uint8_t*& data, size_t& size)
{ {
@ -548,13 +561,12 @@ namespace eevm
} }
else else
{ {
return decode<T>(data, size); return decode_impl<T>(data, size);
} }
} }
// Type helper for decoding single item, forwarding to either decode_tuple // Type helper for decoding multiple items, decoding the first and then
// (to unwrap the types contained in a tuple) or directly to the main // potentially recursing to concatenate the decoded tail
// decode function
template <typename T, typename... Ts> template <typename T, typename... Ts>
std::tuple<T, Ts...> decode_multiple(const uint8_t*& data, size_t& size) std::tuple<T, Ts...> decode_multiple(const uint8_t*& data, size_t& size)
{ {
@ -570,14 +582,15 @@ namespace eevm
} }
} }
// Main decode function. Reads initial length, then either converts a single // Main decode_impl function. Reads initial length, then either converts a
// item from remaining bytes or forwards to decode_multiple // single item from remaining bytes or forwards to decode_multiple
template <typename... Ts> template <typename... Ts>
std::tuple<Ts...> decode(const uint8_t*& data, size_t& size) std::tuple<Ts...> decode_impl(const uint8_t*& data, size_t& size)
{ {
auto [arity, contained_length] = decode_length(data, size); auto [arity, contained_length] = decode_length(data, size);
if constexpr (sizeof...(Ts) == 1 && !is_tuple<std::decay_t<Ts>...>::value) if constexpr (
sizeof...(Ts) == 1 && !is_tuple<std::decay_t<Ts>...>::value)
{ {
if (arity != Arity::Single) if (arity != Arity::Single)
{ {
@ -585,6 +598,7 @@ namespace eevm
} }
size -= contained_length; size -= contained_length;
return std::make_tuple(from_bytes<Ts...>{}(data, contained_length)); return std::make_tuple(from_bytes<Ts...>{}(data, contained_length));
} }
@ -598,9 +612,9 @@ namespace eevm
{ {
if (contained_length != 0) if (contained_length != 0)
{ {
throw decode_error( throw decode_error(fmt::format(
"Expected empty list, but data contains " + "Expected empty list, but data contains {} remaining bytes",
std::to_string(contained_length) + " remaining bytes"); contained_length));
} }
return std::make_tuple(); return std::make_tuple();
@ -608,11 +622,29 @@ namespace eevm
else else
{ {
size -= contained_length; size -= contained_length;
return decode_multiple<Ts...>(data, contained_length); return decode_multiple<Ts...>(data, contained_length);
} }
} }
}
// Helper. Takes ByteString and forwards to contained data+size to main // Core helper. Forwards to decode_impl, ensures entire input has been
// consumed
template <typename... Ts>
std::tuple<Ts...> decode(const uint8_t*& data, size_t& size)
{
auto res = decode_details::decode_impl<Ts...>(data, size);
if (size != 0)
{
throw decode_error(fmt::format(
"Expected to decode entire input, but {} bytes remain", size));
}
return res;
}
// Helper. Takes ByteString and forwards contained data+size to main
// decode function // decode function
template <typename... Ts> template <typename... Ts>
std::tuple<Ts...> decode(const ByteString& bytes) std::tuple<Ts...> decode(const ByteString& bytes)

Просмотреть файл

@ -20,11 +20,15 @@ const auto large_input_decoded = std::make_tuple(
66000u), 66000u),
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua"s); "tempor incididunt ut labore et dolore magna aliqua"s);
const auto large_input_encoded = rlp::to_byte_string(
const std::string large_input_encoded_s =
"\xf8\xa5\xda\x8bHello world\x8dSaluton " "\xf8\xa5\xda\x8bHello world\x8dSaluton "
"Mondo\xcd\xc8\xc1\x01\xc2\x02\x03\xc2\xc1\x04\x83\x01\x01\xd0\xb8zLorem " "Mondo\xcd\xc8\xc1\x01\xc2\x02\x03\xc2\xc1\x04\x83\x01\x01\xd0\xb8zLorem "
"ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod " "ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod "
"tempor incididunt ut labore et dolore magna aliqua"); "tempor incididunt ut labore et dolore magna aliqua";
const auto large_input_encoded = std::vector<uint8_t>(
large_input_encoded_s.begin(), large_input_encoded_s.end());
TEST_CASE("encode" * doctest::test_suite("rlp")) TEST_CASE("encode" * doctest::test_suite("rlp"))
{ {
@ -83,6 +87,7 @@ TEST_CASE("decode" * doctest::test_suite("rlp"))
CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x1}) == 0x1); CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x1}) == 0x1);
CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x7f}) == 0x7f); CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x7f}) == 0x7f);
CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x81, 0x80}) == 0x80); CHECK(rlp::decode_single<size_t>(rlp::ByteString{0x81, 0x80}) == 0x80);
CHECK_THROWS(rlp::decode_single<size_t>(rlp::ByteString{0x81, 0x80, 0x00}));
CHECK(rlp::decode<>(rlp::ByteString{0xc0}) == std::make_tuple()); CHECK(rlp::decode<>(rlp::ByteString{0xc0}) == std::make_tuple());
CHECK(rlp::decode<std::string>(rlp::ByteString{0x80}) == std::make_tuple("")); CHECK(rlp::decode<std::string>(rlp::ByteString{0x80}) == std::make_tuple(""));
@ -123,6 +128,8 @@ TEST_CASE("decode" * doctest::test_suite("rlp"))
rlp::decode<std::tuple<std::tuple<size_t>>>( rlp::decode<std::tuple<std::tuple<size_t>>>(
rlp::ByteString{0xc2, 0xc1, 0x80}) == rlp::ByteString{0xc2, 0xc1, 0x80}) ==
std::make_tuple(std::make_tuple(std::make_tuple(0x0)))); std::make_tuple(std::make_tuple(std::make_tuple(0x0))));
CHECK_THROWS(rlp::decode<std::tuple<std::tuple<size_t>>>(
rlp::ByteString{0xc2, 0xc1, 0x80, 0x00}));
CHECK( CHECK(
rlp::decode_single< rlp::decode_single<