mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-24 22:20:19 +00:00
551 lines
14 KiB
C++
551 lines
14 KiB
C++
#include <xrpl/protocol/Serializer.h>
|
|
|
|
#include <xrpl/basics/Buffer.h>
|
|
#include <xrpl/basics/Slice.h>
|
|
#include <xrpl/basics/base_uint.h>
|
|
#include <xrpl/basics/contract.h>
|
|
#include <xrpl/basics/safe_cast.h>
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/protocol/HashPrefix.h>
|
|
#include <xrpl/protocol/digest.h>
|
|
|
|
#include <boost/endian/conversion.hpp>
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <type_traits>
|
|
|
|
namespace xrpl {
|
|
|
|
int
|
|
Serializer::add16(std::uint16_t i)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.push_back(static_cast<unsigned char>(i >> 8));
|
|
data_.push_back(static_cast<unsigned char>(i & 0xff));
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::add32(HashPrefix p)
|
|
{
|
|
// This should never trigger; the size & type of a hash prefix are
|
|
// integral parts of the protocol and unlikely to ever change.
|
|
static_assert(std::is_same_v<std::uint32_t, std::underlying_type_t<decltype(p)>>);
|
|
|
|
return add32(safeCast<std::uint32_t>(p));
|
|
}
|
|
|
|
template <>
|
|
int
|
|
Serializer::addInteger(unsigned char i)
|
|
{
|
|
return add8(i);
|
|
}
|
|
template <>
|
|
int
|
|
Serializer::addInteger(std::uint16_t i)
|
|
{
|
|
return add16(i);
|
|
}
|
|
template <>
|
|
int
|
|
Serializer::addInteger(std::uint32_t i)
|
|
{
|
|
return add32(i);
|
|
}
|
|
template <>
|
|
int
|
|
Serializer::addInteger(std::uint64_t i)
|
|
{
|
|
return add64(i);
|
|
}
|
|
template <>
|
|
int
|
|
Serializer::addInteger(std::int32_t i)
|
|
{
|
|
return add32(i);
|
|
}
|
|
|
|
int
|
|
Serializer::addRaw(Blob const& vector)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.insert(data_.end(), vector.begin(), vector.end());
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addRaw(Slice slice)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.insert(data_.end(), slice.begin(), slice.end());
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addRaw(Serializer const& s)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.insert(data_.end(), s.begin(), s.end());
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addRaw(void const* ptr, int len)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.insert(data_.end(), static_cast<char const*>(ptr), static_cast<char const*>(ptr) + len);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addFieldID(int type, int name)
|
|
{
|
|
int const ret = data_.size();
|
|
XRPL_ASSERT(
|
|
(type > 0) && (type < 256) && (name > 0) && (name < 256),
|
|
"xrpl::Serializer::addFieldID : inputs inside range");
|
|
|
|
if (type < 16)
|
|
{
|
|
if (name < 16)
|
|
{
|
|
// common type, common name
|
|
data_.push_back(static_cast<unsigned char>((type << 4) | name));
|
|
}
|
|
else
|
|
{
|
|
// common type, uncommon name
|
|
data_.push_back(static_cast<unsigned char>(type << 4));
|
|
data_.push_back(static_cast<unsigned char>(name));
|
|
}
|
|
}
|
|
else if (name < 16)
|
|
{
|
|
// uncommon type, common name
|
|
data_.push_back(static_cast<unsigned char>(name));
|
|
data_.push_back(static_cast<unsigned char>(type));
|
|
}
|
|
else
|
|
{
|
|
// uncommon type, uncommon name
|
|
data_.push_back(static_cast<unsigned char>(0));
|
|
data_.push_back(static_cast<unsigned char>(type));
|
|
data_.push_back(static_cast<unsigned char>(name));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::add8(unsigned char byteValue)
|
|
{
|
|
int const ret = data_.size();
|
|
data_.push_back(byteValue);
|
|
return ret;
|
|
}
|
|
|
|
bool
|
|
Serializer::get8(int& byte, int offset) const
|
|
{
|
|
if (offset >= data_.size())
|
|
return false;
|
|
|
|
byte = data_[offset];
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Serializer::chop(int bytes)
|
|
{
|
|
if (bytes > data_.size())
|
|
return false;
|
|
|
|
data_.resize(data_.size() - bytes);
|
|
return true;
|
|
}
|
|
|
|
uint256
|
|
Serializer::getSHA512Half() const
|
|
{
|
|
return sha512Half(makeSlice(data_));
|
|
}
|
|
|
|
int
|
|
Serializer::addVL(Blob const& vector)
|
|
{
|
|
int const ret = addEncoded(vector.size());
|
|
addRaw(vector);
|
|
XRPL_ASSERT(
|
|
data_.size() == (ret + vector.size() + encodeLengthLength(vector.size())),
|
|
"xrpl::Serializer::addVL : size matches expected");
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addVL(Slice const& slice)
|
|
{
|
|
int const ret = addEncoded(slice.size());
|
|
if (!slice.empty())
|
|
addRaw(slice.data(), slice.size());
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addVL(void const* ptr, int len)
|
|
{
|
|
int const ret = addEncoded(len);
|
|
|
|
if (len != 0)
|
|
addRaw(ptr, len);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
Serializer::addEncoded(int length)
|
|
{
|
|
// Without this, a negative length would fall into the 1 byte case below and
|
|
// be cast to a first byte no header uses. A size too big for int arrives
|
|
// here negative as well, since callers pass sizes through this parameter.
|
|
if (length < kMinValueOfLengthFor1ByteHeader)
|
|
Throw<std::overflow_error>("addEncoded: length is negative or did not fit in an int");
|
|
|
|
std::array<std::byte, kMaxNumberOfBytesInHeader> bytes{};
|
|
int numBytes = 0;
|
|
|
|
if (length <= kMaxValueOfLengthFor1ByteHeader)
|
|
{
|
|
bytes[0] = static_cast<std::byte>(length);
|
|
numBytes = 1;
|
|
}
|
|
else if (length <= kMaxValueOfLengthFor2ByteHeader)
|
|
{
|
|
// Count from the smallest length a 2 byte header covers.
|
|
int const offset = length - kMinValueOfLengthFor2ByteHeader;
|
|
bytes[0] = static_cast<std::byte>(
|
|
kMinValueOfFirstByteFor2ByteHeader + (offset / kNumberOfValuesInOneByte));
|
|
bytes[1] = static_cast<std::byte>(offset % kNumberOfValuesInOneByte);
|
|
numBytes = 2;
|
|
}
|
|
else if (length <= kMaxValueOfLengthFor3ByteHeader)
|
|
{
|
|
int const offset = length - kMinValueOfLengthFor3ByteHeader;
|
|
bytes[0] = static_cast<std::byte>(
|
|
kMinValueOfFirstByteFor3ByteHeader + (offset / kNumberOfValuesInTwoBytes));
|
|
bytes[1] =
|
|
static_cast<std::byte>((offset / kNumberOfValuesInOneByte) % kNumberOfValuesInOneByte);
|
|
bytes[2] = static_cast<std::byte>(offset % kNumberOfValuesInOneByte);
|
|
numBytes = 3;
|
|
}
|
|
else
|
|
{
|
|
Throw<std::overflow_error>("addEncoded: length is too large to encode");
|
|
}
|
|
|
|
return addRaw(bytes.data(), numBytes);
|
|
}
|
|
|
|
int
|
|
Serializer::encodeLengthLength(int length)
|
|
{
|
|
if (length < kMinValueOfLengthFor1ByteHeader)
|
|
{
|
|
Throw<std::overflow_error>(
|
|
"encodeLengthLength: length is negative or did not fit in an int");
|
|
}
|
|
|
|
if (length <= kMaxValueOfLengthFor1ByteHeader)
|
|
return 1;
|
|
|
|
if (length <= kMaxValueOfLengthFor2ByteHeader)
|
|
return 2;
|
|
|
|
if (length <= kMaxValueOfLengthFor3ByteHeader)
|
|
return 3;
|
|
|
|
Throw<std::overflow_error>("encodeLengthLength: length is too large to encode");
|
|
}
|
|
|
|
int
|
|
Serializer::decodeLengthLength(std::byte firstByte)
|
|
{
|
|
int const firstByteValue = std::to_integer<int>(firstByte);
|
|
|
|
if (firstByteValue <= kMaxValueOfFirstByteFor1ByteHeader)
|
|
return 1;
|
|
|
|
if (firstByteValue <= kMaxValueOfFirstByteFor2ByteHeader)
|
|
return 2;
|
|
|
|
if (firstByteValue <= kMaxValueOfFirstByteFor3ByteHeader)
|
|
return 3;
|
|
|
|
Throw<std::overflow_error>("decodeLengthLength: first byte does not start any header");
|
|
}
|
|
|
|
int
|
|
Serializer::decodeVLLength(std::byte firstByte)
|
|
{
|
|
int const length = std::to_integer<int>(firstByte);
|
|
|
|
// A bigger value means a longer header, so it is not a length by itself.
|
|
if (length > kMaxValueOfLengthFor1ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 1 byte: first byte is not a length");
|
|
|
|
return length;
|
|
}
|
|
|
|
int
|
|
Serializer::decodeVLLength(std::byte firstByte, std::byte secondByte)
|
|
{
|
|
int const firstByteValue = std::to_integer<int>(firstByte);
|
|
|
|
if (firstByteValue < kMinValueOfFirstByteFor2ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 2 byte: first byte is below the range");
|
|
|
|
if (firstByteValue > kMaxValueOfFirstByteFor2ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 2 byte: first byte is above the range");
|
|
|
|
// Both bytes are bounded by their own type, and the first one is bounded to
|
|
// the 2 byte range above, so this cannot leave the range the header covers.
|
|
return kMinValueOfLengthFor2ByteHeader +
|
|
((firstByteValue - kMinValueOfFirstByteFor2ByteHeader) * kNumberOfValuesInOneByte) +
|
|
std::to_integer<int>(secondByte);
|
|
}
|
|
|
|
int
|
|
Serializer::decodeVLLength(std::byte firstByte, std::byte secondByte, std::byte thirdByte)
|
|
{
|
|
int const firstByteValue = std::to_integer<int>(firstByte);
|
|
|
|
if (firstByteValue < kMinValueOfFirstByteFor3ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 3 byte: first byte is below the range");
|
|
|
|
if (firstByteValue > kMaxValueOfFirstByteFor3ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 3 byte: first byte is above the range");
|
|
|
|
int const length = kMinValueOfLengthFor3ByteHeader +
|
|
((firstByteValue - kMinValueOfFirstByteFor3ByteHeader) * kNumberOfValuesInTwoBytes) +
|
|
(std::to_integer<int>(secondByte) * kNumberOfValuesInOneByte) +
|
|
std::to_integer<int>(thirdByte);
|
|
|
|
// A 3 byte header reaches further than kMaxValueOfLengthFor3ByteHeader, which
|
|
// is as far as the encoder goes. Refuse the rest, so every length accepted
|
|
// here is one that can be written back.
|
|
if (length > kMaxValueOfLengthFor3ByteHeader)
|
|
Throw<std::overflow_error>("decodeVLLength 3 byte: length is too large to re-encode");
|
|
|
|
return length;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
SerialIter::SerialIter(void const* data, std::size_t size) noexcept
|
|
: p_(reinterpret_cast<std::uint8_t const*>(data)), remain_(size)
|
|
{
|
|
}
|
|
|
|
void
|
|
SerialIter::reset() noexcept
|
|
{
|
|
p_ -= used_;
|
|
remain_ += used_;
|
|
used_ = 0;
|
|
}
|
|
|
|
void
|
|
SerialIter::skip(int length)
|
|
{
|
|
if (remain_ < length)
|
|
Throw<std::runtime_error>("invalid SerialIter skip");
|
|
p_ += length;
|
|
used_ += length;
|
|
remain_ -= length;
|
|
}
|
|
|
|
unsigned char
|
|
SerialIter::get8()
|
|
{
|
|
if (remain_ < 1)
|
|
Throw<std::runtime_error>("invalid SerialIter get8");
|
|
unsigned char const t = *p_;
|
|
++p_;
|
|
++used_;
|
|
--remain_;
|
|
return t;
|
|
}
|
|
|
|
std::uint16_t
|
|
SerialIter::get16()
|
|
{
|
|
if (remain_ < 2)
|
|
Throw<std::runtime_error>("invalid SerialIter get16");
|
|
auto t = p_;
|
|
p_ += 2;
|
|
used_ += 2;
|
|
remain_ -= 2;
|
|
return (std::uint64_t(t[0]) << 8) + std::uint64_t(t[1]);
|
|
}
|
|
|
|
std::uint32_t
|
|
SerialIter::get32()
|
|
{
|
|
if (remain_ < 4)
|
|
Throw<std::runtime_error>("invalid SerialIter get32");
|
|
auto t = p_;
|
|
p_ += 4;
|
|
used_ += 4;
|
|
remain_ -= 4;
|
|
return (std::uint64_t(t[0]) << 24) + (std::uint64_t(t[1]) << 16) + (std::uint64_t(t[2]) << 8) +
|
|
std::uint64_t(t[3]);
|
|
}
|
|
|
|
std::uint64_t
|
|
SerialIter::get64()
|
|
{
|
|
if (remain_ < 8)
|
|
Throw<std::runtime_error>("invalid SerialIter get64");
|
|
auto t = p_;
|
|
p_ += 8;
|
|
used_ += 8;
|
|
remain_ -= 8;
|
|
return (std::uint64_t(t[0]) << 56) + (std::uint64_t(t[1]) << 48) + (std::uint64_t(t[2]) << 40) +
|
|
(std::uint64_t(t[3]) << 32) + (std::uint64_t(t[4]) << 24) + (std::uint64_t(t[5]) << 16) +
|
|
(std::uint64_t(t[6]) << 8) + std::uint64_t(t[7]);
|
|
}
|
|
|
|
std::int32_t
|
|
SerialIter::geti32()
|
|
{
|
|
if (remain_ < 4)
|
|
Throw<std::runtime_error>("invalid SerialIter geti32");
|
|
auto t = p_;
|
|
p_ += 4;
|
|
used_ += 4;
|
|
remain_ -= 4;
|
|
return boost::endian::load_big_s32(t);
|
|
}
|
|
|
|
std::int64_t
|
|
SerialIter::geti64()
|
|
{
|
|
if (remain_ < 8)
|
|
Throw<std::runtime_error>("invalid SerialIter geti64");
|
|
auto t = p_;
|
|
p_ += 8;
|
|
used_ += 8;
|
|
remain_ -= 8;
|
|
return boost::endian::load_big_s64(t);
|
|
}
|
|
|
|
void
|
|
SerialIter::getFieldID(int& type, int& name)
|
|
{
|
|
type = get8();
|
|
name = type & 15;
|
|
type >>= 4;
|
|
|
|
if (type == 0)
|
|
{
|
|
// uncommon type
|
|
type = get8();
|
|
if (type < 16)
|
|
Throw<std::runtime_error>("gFID: uncommon type out of range " + std::to_string(type));
|
|
}
|
|
|
|
if (name == 0)
|
|
{
|
|
// uncommon name
|
|
name = get8();
|
|
if (name < 16)
|
|
Throw<std::runtime_error>("gFID: uncommon name out of range " + std::to_string(name));
|
|
}
|
|
}
|
|
|
|
// getRaw for blob or buffer
|
|
template <class T>
|
|
T
|
|
SerialIter::getRawHelper(int size)
|
|
{
|
|
static_assert(std::is_same_v<T, Blob> || std::is_same_v<T, Buffer>);
|
|
if (remain_ < size)
|
|
Throw<std::runtime_error>("invalid SerialIter getRaw");
|
|
T result(size);
|
|
if (size != 0)
|
|
{
|
|
// It's normally safe to call memcpy with size set to 0 (see the
|
|
// C99 standard 7.21.1/2). However, here this could mean that
|
|
// result.data would be null, which would trigger undefined behavior.
|
|
std::memcpy(result.data(), p_, size);
|
|
p_ += size;
|
|
used_ += size;
|
|
remain_ -= size;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// VFALCO DEPRECATED Returns a copy
|
|
Blob
|
|
SerialIter::getRaw(int size)
|
|
{
|
|
return getRawHelper<Blob>(size);
|
|
}
|
|
|
|
int
|
|
SerialIter::getVLDataLength()
|
|
{
|
|
std::byte const firstByte{get8()};
|
|
int datLen = 0;
|
|
int const lenLen = Serializer::decodeLengthLength(firstByte);
|
|
if (lenLen == 1)
|
|
{
|
|
datLen = Serializer::decodeVLLength(firstByte);
|
|
}
|
|
else if (lenLen == 2)
|
|
{
|
|
std::byte const secondByte{get8()};
|
|
datLen = Serializer::decodeVLLength(firstByte, secondByte);
|
|
}
|
|
else
|
|
{
|
|
XRPL_ASSERT(lenLen == 3, "xrpl::SerialIter::getVLDataLength : lenLen is 3");
|
|
std::byte const secondByte{get8()};
|
|
std::byte const thirdByte{get8()};
|
|
datLen = Serializer::decodeVLLength(firstByte, secondByte, thirdByte);
|
|
}
|
|
return datLen;
|
|
}
|
|
|
|
Slice
|
|
SerialIter::getSlice(std::size_t bytes)
|
|
{
|
|
if (bytes > remain_)
|
|
Throw<std::runtime_error>("invalid SerialIter getSlice");
|
|
Slice const s(p_, bytes);
|
|
p_ += bytes;
|
|
used_ += bytes;
|
|
remain_ -= bytes;
|
|
return s;
|
|
}
|
|
|
|
// VFALCO DEPRECATED Returns a copy
|
|
Blob
|
|
SerialIter::getVL()
|
|
{
|
|
return getRaw(getVLDataLength());
|
|
}
|
|
|
|
Buffer
|
|
SerialIter::getVLBuffer()
|
|
{
|
|
return getRawHelper<Buffer>(getVLDataLength());
|
|
}
|
|
|
|
} // namespace xrpl
|