Serialization (part2): application

This commit is contained in:
Jason Rhinelander 2020-06-02 00:08:48 -03:00
parent 799aa6aed5
commit a506790f1c
27 changed files with 842 additions and 1052 deletions

View File

@ -976,12 +976,13 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons
unsigned int unprunable_size = tx.unprunable_size;
if (unprunable_size == 0)
{
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = const_cast<cryptonote::transaction&>(tx).serialize_base(ba);
if (!r)
throw0(DB_ERROR("Failed to serialize pruned tx"));
unprunable_size = ss.str().size();
serialization::binary_string_archiver ba;
try {
const_cast<cryptonote::transaction&>(tx).serialize_base(ba);
} catch (const std::exception& e) {
throw0(DB_ERROR("Failed to serialize pruned tx: "s + e.what()));
}
unprunable_size = ba.str().size();
}
if (unprunable_size > blob.size())
@ -5504,12 +5505,13 @@ void BlockchainLMDB::migrate_1_2()
transaction tx;
if (!parse_and_validate_tx_from_blob(bd, tx))
throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db"));
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = tx.serialize_base(ba);
if (!r)
throw0(DB_ERROR("Failed to serialize pruned tx"));
std::string pruned = ss.str();
serialization::binary_string_archiver ba;
try {
tx.serialize_base(ba);
} catch (const std::exception& e) {
throw0(DB_ERROR("Failed to serialize pruned tx: "s + e.what()));
}
std::string pruned = ba.str();
if (pruned.size() > bd.size())
throw0(DB_ERROR("Pruned tx is larger than raw tx"));

View File

@ -302,23 +302,19 @@ static void close()
static std::string compress_ring(const std::vector<uint64_t> &ring, std::string s = "")
{
const size_t sz = s.size();
s.resize(s.size() + 12 * ring.size());
char *ptr = (char*)s.data() + sz;
s.reserve(s.size() + tools::VARINT_MAX_LENGTH<uint64_t> * ring.size());
auto ins = std::back_inserter(s);
for (uint64_t out: ring)
tools::write_varint(ptr, out);
if (ptr > s.data() + sz + 12 * ring.size())
throw std::runtime_error("varint output overflow");
s.resize(ptr - s.data());
tools::write_varint(ins, out);
return s;
}
static std::string compress_ring(uint64_t amount, const std::vector<uint64_t> &ring)
{
char s[12], *ptr = s;
tools::write_varint(ptr, amount);
if (ptr > s + sizeof(s))
throw std::runtime_error("varint output overflow");
return compress_ring(ring, std::string(s, ptr-s));
std::string s;
s.reserve(tools::VARINT_MAX_LENGTH<uint64_t> * (1 + ring.size()));
tools::write_varint(std::back_inserter(s), amount);
return compress_ring(ring, std::move(s));
}
static std::vector<uint64_t> decompress_ring(const std::string &s)
@ -393,13 +389,13 @@ static bool for_all_transactions(const std::string &filename, uint64_t &start_id
continue;
cryptonote::transaction_prefix tx;
blobdata bd;
bd.assign(reinterpret_cast<char*>(v.mv_data), v.mv_size);
std::stringstream ss;
ss << bd;
binary_archive<false> ba(ss);
bool r = do_serialize(ba, tx);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
try {
std::string_view bd{static_cast<const char*>(v.mv_data), v.mv_size};
serialization::parse_binary(bd, tx);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse transaction from blob: " << e.what());
return false;
}
start_idx = *(uint64_t*)k.mv_data;
if (!f(tx)) {

View File

@ -40,8 +40,7 @@
#include "bootstrap_serialization.h"
#include "blocks/blocks.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "serialization/binary_utils.h" // dump_binary(), parse_binary()
#include "serialization/json_utils.h" // dump_json()
#include "serialization/binary_utils.h"
#include "include_base_utils.h"
#include "cryptonote_core/cryptonote_core.h"
@ -249,7 +248,6 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
// 4 byte magic + (currently) 1024 byte header structures
bootstrap.seek_to_first_chunk(import_file);
std::string str1;
char buffer1[1024];
char buffer_block[BUFFER_SIZE];
block b;
@ -314,10 +312,10 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
}
bytes_read += sizeof(chunk_size);
str1.assign(buffer1, sizeof(chunk_size));
if (! ::serialization::parse_binary(str1, chunk_size))
{
throw std::runtime_error("Error in deserialization of chunk size");
try {
serialization::parse_binary(std::string_view{buffer1, sizeof(chunk_size)}, chunk_size);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of chunk size: "s + e.what());
}
MDEBUG("chunk_size: " << chunk_size);
@ -365,10 +363,12 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
try
{
str1.assign(buffer_block, chunk_size);
bootstrap::block_package bp;
if (! ::serialization::parse_binary(str1, bp))
throw std::runtime_error("Error in deserialization of chunk");
try {
serialization::parse_binary(std::string_view{buffer_block, chunk_size}, bp);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of chunk"s + e.what());
}
int display_interval = 1000;
int progress_interval = 10;

View File

@ -29,7 +29,6 @@
#include "bootstrap_serialization.h"
#include "serialization/binary_utils.h" // dump_binary(), parse_binary()
#include "serialization/json_utils.h" // dump_json()
#include "bootstrap_file.h"
@ -117,9 +116,10 @@ bool BootstrapFile::initialize_file()
const uint32_t file_magic = blockchain_raw_magic;
std::string blob;
if (! ::serialization::dump_binary(file_magic, blob))
{
throw std::runtime_error("Error in serialization of file magic");
try {
blob = serialization::dump_binary(file_magic);
} catch (const std::exception& e) {
throw std::runtime_error("Error in serialization of file magic: "s + e.what());
}
*m_raw_data_file << blob;
@ -142,9 +142,10 @@ bool BootstrapFile::initialize_file()
MDEBUG("bootstrap::file_info size: " << bd.size());
bd_size = bd.size();
if (! ::serialization::dump_binary(bd_size, blob))
{
throw std::runtime_error("Error in serialization of bootstrap::file_info size");
try {
blob = serialization::dump_binary(bd_size);
} catch (const std::exception& e) {
throw std::runtime_error("Error in serialization of bootstrap::file_info size: "s + e.what());
}
output_stream_header << blob;
output_stream_header << bd;
@ -153,9 +154,10 @@ bool BootstrapFile::initialize_file()
MDEBUG("bootstrap::blocks_info size: " << bd.size());
bd_size = bd.size();
if (! ::serialization::dump_binary(bd_size, blob))
{
throw std::runtime_error("Error in serialization of bootstrap::blocks_info size");
try {
blob = serialization::dump_binary(bd_size);
} catch (const std::exception& e) {
throw std::runtime_error("Error in serialization of bootstrap::blocks_info size: "s + e.what());
}
output_stream_header << blob;
output_stream_header << bd;
@ -180,9 +182,10 @@ void BootstrapFile::flush_chunk()
}
std::string blob;
if (! ::serialization::dump_binary(chunk_size, blob))
{
throw std::runtime_error("Error in serialization of chunk size");
try {
blob = serialization::dump_binary(chunk_size);
} catch (const std::exception& e) {
throw std::runtime_error("Error in serialization of chunk size: "s + e.what());
}
*m_raw_data_file << blob;
@ -334,8 +337,11 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
throw std::runtime_error("Error reading expected number of bytes");
str1.assign(buf1, sizeof(file_magic));
if (! ::serialization::parse_binary(str1, file_magic))
throw std::runtime_error("Error in deserialization of file_magic");
try {
serialization::parse_binary(str1, file_magic);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of file_magic: "s + e.what());
}
if (file_magic != blockchain_raw_magic)
{
@ -351,8 +357,11 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
str1.assign(buf1, sizeof(buflen_file_info));
if (! import_file)
throw std::runtime_error("Error reading expected number of bytes");
if (! ::serialization::parse_binary(str1, buflen_file_info))
throw std::runtime_error("Error in deserialization of buflen_file_info");
try {
serialization::parse_binary(str1, buflen_file_info);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of buflen_file_info: "s + e.what());
}
MINFO("bootstrap::file_info size: " << buflen_file_info);
if (buflen_file_info > sizeof(buf1))
@ -362,8 +371,11 @@ uint64_t BootstrapFile::seek_to_first_chunk(std::ifstream& import_file)
throw std::runtime_error("Error reading expected number of bytes");
str1.assign(buf1, buflen_file_info);
bootstrap::file_info bfi;
if (! ::serialization::parse_binary(str1, bfi))
throw std::runtime_error("Error in deserialization of bootstrap::file_info");
try {
serialization::parse_binary(str1, bfi);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of bootstrap::file_info: "s + e.what());
}
MINFO("bootstrap file v" << unsigned(bfi.major_version) << "." << unsigned(bfi.minor_version));
MINFO("bootstrap magic size: " << sizeof(file_magic));
MINFO("bootstrap header size: " << bfi.header_size);
@ -392,8 +404,11 @@ uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks,
}
bytes_read += sizeof(chunk_size);
str1.assign(buf1, sizeof(chunk_size));
if (! ::serialization::parse_binary(str1, chunk_size))
throw std::runtime_error("Error in deserialization of chunk_size");
try {
serialization::parse_binary(str1, chunk_size);
} catch (const std::exception& e) {
throw std::runtime_error("Error in deserialization of chunk_size: "s + e.what());
}
MDEBUG("chunk_size: " << chunk_size);
if (chunk_size > BUFFER_SIZE)

View File

@ -197,12 +197,11 @@ namespace crypto {
void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
struct {
key_derivation derivation;
char output_index[(sizeof(size_t) * 8 + 6) / 7];
char output_index[tools::VARINT_MAX_LENGTH<size_t>];
} buf;
char *end = buf.output_index;
buf.derivation = derivation;
tools::write_varint(end, output_index);
assert(end <= buf.output_index + sizeof buf.output_index);
hash_to_scalar(&buf, end - reinterpret_cast<char *>(&buf), res);
}

View File

@ -38,7 +38,6 @@
#include "serialization/vector.h"
#include "serialization/binary_archive.h"
#include "serialization/json_archive.h"
#include "serialization/debug_archive.h"
#include "serialization/crypto.h"
#include "serialization/keyvalue_serialization.h" // eepe named serialization
#include "cryptonote_config.h"
@ -149,10 +148,6 @@ namespace cryptonote
};
template<typename T> static inline unsigned int getpos(T &ar) { return 0; }
template<> inline unsigned int getpos(binary_archive<true> &ar) { return ar.stream().tellp(); }
template<> inline unsigned int getpos(binary_archive<false> &ar) { return ar.stream().tellg(); }
enum class txversion : uint16_t {
v0 = 0,
v1,
@ -213,7 +208,7 @@ namespace cryptonote
FIELD(vin)
FIELD(vout)
if (version >= txversion::v3_per_output_unlock_times && vout.size() != output_unlock_times.size())
return false;
throw std::invalid_argument{"v3 tx without correct unlock times"};
FIELD(extra)
if (version >= txversion::v4_tx_types)
ENUM_FIELD_N("type", type, type < txtype::_count);
@ -280,103 +275,96 @@ namespace cryptonote
void set_blob_size(size_t sz) { blob_size = sz; set_blob_size_valid(true); }
BEGIN_SERIALIZE_OBJECT()
if (!typename Archive<W>::is_saving())
constexpr bool Binary = serialization::is_binary<Archive>;
if (Archive::is_deserializer)
{
set_hash_valid(false);
set_blob_size_valid(false);
}
const unsigned int start_pos = getpos(ar);
const unsigned int start_pos = Binary ? ar.streampos() : 0;
FIELDS(*static_cast<transaction_prefix *>(this))
serialization::value(ar, static_cast<transaction_prefix&>(*this));
if (std::is_same<Archive<W>, binary_archive<W>>())
prefix_size = getpos(ar) - start_pos;
if (Binary)
prefix_size = ar.streampos() - start_pos;
if (version == txversion::v1)
{
if (std::is_same<Archive<W>, binary_archive<W>>())
unprunable_size = getpos(ar) - start_pos;
if (Binary)
unprunable_size = ar.streampos() - start_pos;
ar.tag("signatures");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
bool signatures_not_expected = signatures.empty();
if (!signatures_not_expected && vin.size() != signatures.size())
return false;
auto arr = ar.begin_array();
if (Archive::is_deserializer)
signatures.resize(vin.size());
bool signatures_expected = !signatures.empty();
if (signatures_expected && vin.size() != signatures.size())
throw std::invalid_argument{"Incorrect number of signatures"};
if (!pruned) for (size_t i = 0; i < vin.size(); ++i)
const size_t vin_sigs = pruned ? 0 : vin.size();
for (size_t i = 0; i < vin_sigs; ++i)
{
size_t signature_size = get_signature_size(vin[i]);
if (signatures_not_expected)
if (!signatures_expected)
{
if (0 == signature_size)
continue;
else
return false;
if (signature_size > 0)
throw std::invalid_argument{"Invalid unexpected signature"};
continue;
}
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]);
if (signature_size != signatures[i].size())
return false;
if (Archive::is_deserializer)
signatures[i].resize(signature_size);
else if (signature_size != signatures[i].size())
throw std::invalid_argument{"Invalid signature size (expected " + std::to_string(signature_size) + ", have " + std::to_string(signatures[i].size()) + ")"};
FIELDS(signatures[i]);
if (vin.size() - i > 1)
ar.delimit_array();
value(arr.element(), signatures[i]);
}
ar.end_array();
}
else
{
ar.tag("rct_signatures");
if (!vin.empty())
{
ar.begin_object();
bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
if (!r || !ar.stream().good()) return false;
ar.end_object();
{
auto obj = ar.begin_object();
rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
}
if (std::is_same<Archive<W>, binary_archive<W>>())
unprunable_size = getpos(ar) - start_pos;
if (Binary)
unprunable_size = ar.streampos() - start_pos;
if (!pruned && rct_signatures.type != rct::RCTTypeNull)
{
ar.tag("rctsig_prunable");
ar.begin_object();
r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
if (!r || !ar.stream().good()) return false;
ar.end_object();
auto obj = ar.begin_object();
rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(),
vin.size() > 0 && std::holds_alternative<txin_to_key>(vin[0]) ? std::get<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
}
}
}
if (!typename Archive<W>::is_saving())
if (Archive::is_deserializer)
pruned = false;
END_SERIALIZE()
template<bool W, template <bool> class Archive>
bool serialize_base(Archive<W> &ar)
template<class Archive>
void serialize_base(Archive& ar)
{
FIELDS(*static_cast<transaction_prefix *>(this))
serialization::value(ar, static_cast<transaction_prefix&>(*this));
if (version == txversion::v1)
{
}
else
if (version != txversion::v1)
{
// FIXME - seems wrong to tag with no value if vin.empty?
ar.tag("rct_signatures");
if (!vin.empty())
{
ar.begin_object();
bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
if (!r || !ar.stream().good()) return false;
ar.end_object();
auto obj = ar.begin_object();
rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size());
}
}
if (!typename Archive<W>::is_saving())
if (Archive::is_deserializer)
pruned = true;
return ar.stream().good();
}
private:
@ -476,14 +464,14 @@ namespace cryptonote
mutable crypto::hash hash;
BEGIN_SERIALIZE_OBJECT()
if (!typename Archive<W>::is_saving())
if (Archive::is_deserializer)
set_hash_valid(false);
FIELDS(*static_cast<block_header *>(this))
FIELDS(static_cast<block_header&>(*this))
FIELD(miner_tx)
FIELD(tx_hashes)
if (tx_hashes.size() > CRYPTONOTE_MAX_TX_PER_BLOCK)
return false;
throw std::invalid_argument{"too many txs in block"};
END_SERIALIZE()
};
@ -615,32 +603,12 @@ namespace std {
BLOB_SERIALIZER(cryptonote::txout_to_key);
BLOB_SERIALIZER(cryptonote::txout_to_scripthash);
VARIANT_TAG(binary_archive, cryptonote::txin_gen, 0xff);
VARIANT_TAG(binary_archive, cryptonote::txin_to_script, 0x0);
VARIANT_TAG(binary_archive, cryptonote::txin_to_scripthash, 0x1);
VARIANT_TAG(binary_archive, cryptonote::txin_to_key, 0x2);
VARIANT_TAG(binary_archive, cryptonote::txout_to_script, 0x0);
VARIANT_TAG(binary_archive, cryptonote::txout_to_scripthash, 0x1);
VARIANT_TAG(binary_archive, cryptonote::txout_to_key, 0x2);
VARIANT_TAG(binary_archive, cryptonote::transaction, 0xcc);
VARIANT_TAG(binary_archive, cryptonote::block, 0xbb);
VARIANT_TAG(json_archive, cryptonote::txin_gen, "gen");
VARIANT_TAG(json_archive, cryptonote::txin_to_script, "script");
VARIANT_TAG(json_archive, cryptonote::txin_to_scripthash, "scripthash");
VARIANT_TAG(json_archive, cryptonote::txin_to_key, "key");
VARIANT_TAG(json_archive, cryptonote::txout_to_script, "script");
VARIANT_TAG(json_archive, cryptonote::txout_to_scripthash, "scripthash");
VARIANT_TAG(json_archive, cryptonote::txout_to_key, "key");
VARIANT_TAG(json_archive, cryptonote::transaction, "tx");
VARIANT_TAG(json_archive, cryptonote::block, "block");
VARIANT_TAG(debug_archive, cryptonote::txin_gen, "gen");
VARIANT_TAG(debug_archive, cryptonote::txin_to_script, "script");
VARIANT_TAG(debug_archive, cryptonote::txin_to_scripthash, "scripthash");
VARIANT_TAG(debug_archive, cryptonote::txin_to_key, "key");
VARIANT_TAG(debug_archive, cryptonote::txout_to_script, "script");
VARIANT_TAG(debug_archive, cryptonote::txout_to_scripthash, "scripthash");
VARIANT_TAG(debug_archive, cryptonote::txout_to_key, "key");
VARIANT_TAG(debug_archive, cryptonote::transaction, "tx");
VARIANT_TAG(debug_archive, cryptonote::block, "block");
VARIANT_TAG(cryptonote::txin_gen, "gen", 0xff);
VARIANT_TAG(cryptonote::txin_to_script, "script", 0x0);
VARIANT_TAG(cryptonote::txin_to_scripthash, "scripthash", 0x1);
VARIANT_TAG(cryptonote::txin_to_key, "key", 0x2);
VARIANT_TAG(cryptonote::txout_to_script, "script", 0x0);
VARIANT_TAG(cryptonote::txout_to_scripthash, "scripthash", 0x1);
VARIANT_TAG(cryptonote::txout_to_key, "key", 0x2);
VARIANT_TAG(cryptonote::transaction, "tx", 0xcc);
VARIANT_TAG(cryptonote::block, "block", 0xbb);

View File

@ -247,24 +247,21 @@ namespace cryptonote {
return false;
}
if (info.has_payment_id)
{
integrated_address iadr;
if (!::serialization::parse_binary(data, iadr))
try {
if (info.has_payment_id)
{
LOG_PRINT_L1("Account public address keys can't be parsed");
return false;
integrated_address iadr;
serialization::parse_binary(data, iadr);
info.address = iadr.adr;
info.payment_id = iadr.payment_id;
}
info.address = iadr.adr;
info.payment_id = iadr.payment_id;
}
else
{
if (!::serialization::parse_binary(data, info.address))
else
{
LOG_PRINT_L1("Account public address keys can't be parsed");
return false;
serialization::parse_binary(data, info.address);
}
} catch (const std::exception& e) {
LOG_PRINT_L1("Account public address keys can't be parsed: "s + e.what());
return false;
}
if (!crypto::check_key(info.address.m_spend_public_key) || !crypto::check_key(info.address.m_view_public_key))

View File

@ -31,11 +31,13 @@
#include <atomic>
#include <boost/algorithm/string.hpp>
#include <lokimq/hex.h>
#include "wipeable_string.h"
#include "string_tools.h"
#include "common/i18n.h"
#include "common/osrb.h"
#include "common/meta.h"
#include "serialization/string.h"
#include "serialization/binary_utils.h"
#include "cryptonote_format_utils.h"
#include "cryptonote_config.h"
#include "crypto/crypto.h"
@ -123,10 +125,8 @@ namespace cryptonote
//---------------------------------------------------------------
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h)
{
std::ostringstream s;
binary_archive<true> a(s);
::serialization::serialize(a, const_cast<transaction_prefix&>(tx));
crypto::cn_fast_hash(s.str().data(), s.str().size(), h);
std::string str = serialization::dump_binary(const_cast<transaction_prefix&>(tx));
crypto::cn_fast_hash(str.data(), str.size(), h);
}
//---------------------------------------------------------------
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
@ -222,44 +222,56 @@ namespace cryptonote
#endif
//---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx)
{
BINARY_ARCHIVE_STREAM(is, tx_blob);
binary_archive<false> ba(is);
bool r = ::serialization::serialize(ba, tx);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse and validate transaction from blob");
serialization::binary_string_unarchiver ba{tx_blob};
try {
serialization::serialize(ba, tx);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse and validate transaction from blob: " << e.what());
return false;
}
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
tx.invalidate_hashes();
tx.set_blob_size(tx_blob.size());
return true;
}
//---------------------------------------------------------------
bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx)
bool parse_and_validate_tx_base_from_blob(const std::string_view tx_blob, transaction& tx)
{
BINARY_ARCHIVE_STREAM(is, tx_blob);
binary_archive<false> ba(is);
bool r = tx.serialize_base(ba);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction base from blob");
serialization::binary_string_unarchiver ba{tx_blob};
try {
tx.serialize_base(ba);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse transaction base from blob: " << e.what());
return false;
}
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, true), false, "Failed to expand transaction data");
tx.invalidate_hashes();
return true;
}
//---------------------------------------------------------------
bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx)
bool parse_and_validate_tx_prefix_from_blob(const std::string_view tx_blob, transaction_prefix& tx)
{
BINARY_ARCHIVE_STREAM(is, tx_blob);
binary_archive<false> ba(is);
bool r = ::serialization::serialize_noeof(ba, tx);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction prefix from blob");
serialization::binary_string_unarchiver ba{tx_blob};
try {
serialization::value(ba, tx);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse transaction prefix from blob: " << e.what());
return false;
}
return true;
}
//---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash)
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx, crypto::hash& tx_hash)
{
BINARY_ARCHIVE_STREAM(is, tx_blob);
binary_archive<false> ba(is);
bool r = ::serialization::serialize(ba, tx);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse and validate transaction from blob + hash");
serialization::binary_string_unarchiver ba{tx_blob};
try {
serialization::serialize(ba, tx);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse and validate transaction from blob + hash: " << e.what());
return false;
}
CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data");
tx.invalidate_hashes();
//TODO: validate tx
@ -267,7 +279,7 @@ namespace cryptonote
return get_transaction_hash(tx, tx_hash);
}
//---------------------------------------------------------------
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
{
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash))
return false;
@ -275,22 +287,14 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool is_v1_tx(const blobdata_ref& tx_blob)
bool is_v1_tx(const std::string_view tx_blob)
{
uint64_t version;
const char* begin = static_cast<const char*>(tx_blob.data());
const char* end = begin + tx_blob.size();
int read = tools::read_varint(begin, end, version);
if (read <= 0)
if (tools::read_varint(tx_blob, version) <= 0)
throw std::runtime_error("Internal error getting transaction version");
return version <= 1;
}
//---------------------------------------------------------------
bool is_v1_tx(const blobdata& tx_blob)
{
return is_v1_tx(blobdata_ref{tx_blob.data(), tx_blob.size()});
}
//---------------------------------------------------------------
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev)
{
crypto::key_derivation recv_derivation{};
@ -486,18 +490,11 @@ namespace cryptonote
//---------------------------------------------------------------
uint64_t get_transaction_weight(const transaction &tx)
{
size_t blob_size;
if (tx.is_blob_size_valid())
{
blob_size = tx.blob_size;
}
else
{
std::ostringstream s;
binary_archive<true> a(s);
::serialization::serialize(a, const_cast<transaction&>(tx));
blob_size = s.str().size();
}
size_t blob_size =
tx.is_blob_size_valid()
? tx.blob_size
: serialization::dump_binary(const_cast<transaction&>(tx)).size();
return get_transaction_weight(tx, blob_size);
}
//---------------------------------------------------------------
@ -534,128 +531,45 @@ namespace cryptonote
return r;
}
//---------------------------------------------------------------
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
[[nodiscard]] bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields)
{
tx_extra_fields.clear();
if(tx_extra.empty())
return true;
BINARY_ARCHIVE_STREAM(iss, tx_extra);
binary_archive<false> ar(iss);
serialization::binary_string_unarchiver ar{tx_extra};
bool eof = false;
while (!eof)
{
tx_extra_field field;
bool r = ::do_serialize(ar, field);
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
tx_extra_fields.push_back(field);
std::ios_base::iostate state = iss.rdstate();
eof = (EOF == iss.peek());
iss.clear(state);
}
CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
return true;
}
//---------------------------------------------------------------
template<typename T>
static bool pick(binary_archive<true> &ar, std::vector<tx_extra_field> &fields, uint8_t tag)
{
std::vector<tx_extra_field>::iterator it;
while ((it = std::find_if(fields.begin(), fields.end(), [](const tx_extra_field &f) { return f.type() == typeid(T); })) != fields.end())
{
bool r = ::do_serialize(ar, tag);
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
r = ::do_serialize(ar, boost::get<T>(*it));
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to serialize tx extra field");
fields.erase(it);
}
return true;
}
//---------------------------------------------------------------
bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial)
{
std::vector<tx_extra_field> tx_extra_fields;
if(tx_extra.empty())
{
sorted_tx_extra.clear();
return true;
}
BINARY_ARCHIVE_STREAM(iss, tx_extra);
binary_archive<false> ar(iss);
bool eof = false;
size_t processed = 0;
while (!eof)
{
tx_extra_field field;
bool r = ::do_serialize(ar, field);
if (!r)
{
MWARNING("failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
if (!allow_partial)
return false;
break;
}
tx_extra_fields.push_back(field);
processed = iss.tellg();
std::ios_base::iostate state = iss.rdstate();
eof = (EOF == iss.peek());
iss.clear(state);
}
if (!::serialization::check_stream_state(ar))
{
MWARNING("failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
if (!allow_partial)
return false;
}
MTRACE("Sorted " << processed << "/" << tx_extra.size());
std::ostringstream oss;
binary_archive<true> nar(oss);
// sort by:
if (!pick<tx_extra_pub_key> (nar, tx_extra_fields, TX_EXTRA_TAG_PUBKEY)) return false;
if (!pick<tx_extra_service_node_winner>(nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_WINNER)) return false;
if (!pick<tx_extra_additional_pub_keys>(nar, tx_extra_fields, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS)) return false;
if (!pick<tx_extra_nonce> (nar, tx_extra_fields, TX_EXTRA_NONCE)) return false;
if (!pick<tx_extra_service_node_register> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_REGISTER)) return false;
if (!pick<tx_extra_service_node_deregister_old> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_DEREG_OLD)) return false;
if (!pick<tx_extra_service_node_state_change> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE)) return false;
if (!pick<tx_extra_service_node_contributor> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR)) return false;
if (!pick<tx_extra_service_node_pubkey> (nar, tx_extra_fields, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY)) return false;
if (!pick<tx_extra_tx_secret_key> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_SECRET_KEY)) return false;
if (!pick<tx_extra_loki_name_system> (nar, tx_extra_fields, TX_EXTRA_TAG_LOKI_NAME_SYSTEM)) return false;
if (!pick<tx_extra_tx_key_image_proofs> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS)) return false;
if (!pick<tx_extra_tx_key_image_unlock> (nar, tx_extra_fields, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK)) return false;
if (!pick<tx_extra_burn> (nar, tx_extra_fields, TX_EXTRA_TAG_BURN)) return false;
if (!pick<tx_extra_merge_mining_tag> (nar, tx_extra_fields, TX_EXTRA_MERGE_MINING_TAG)) return false;
if (!pick<tx_extra_mysterious_minergate> (nar, tx_extra_fields, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG)) return false;
if (!pick<tx_extra_padding> (nar, tx_extra_fields, TX_EXTRA_TAG_PADDING)) return false;
// if not empty, someone added a new type and did not add a case above
if (!tx_extra_fields.empty())
{
MERROR("tx_extra_fields not empty after sorting, someone forgot to add a case above");
try {
serialization::deserialize_all(ar, tx_extra_fields);
} catch (const std::exception& e) {
MWARNING(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
return false;
}
std::string oss_str = oss.str();
if (allow_partial && processed < tx_extra.size())
{
MDEBUG("Appending unparsed data");
oss_str += std::string((const char*)tx_extra.data() + processed, tx_extra.size() - processed);
return true;
}
//---------------------------------------------------------------
[[nodiscard]] bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra)
{
std::vector<tx_extra_field> tx_extra_fields;
if (!parse_tx_extra(tx_extra, tx_extra_fields))
return false;
// Sort according to the order of variant alternatives in the variant itself
std::stable_sort(tx_extra_fields.begin(), tx_extra_fields.end(), [](auto& a, auto& b) { return a.index() < b.index(); });
serialization::binary_string_archiver ar;
try {
for (auto& f : tx_extra_fields)
serialization::value(ar, f);
} catch (const std::exception& e) {
LOG_PRINT_L1("failed to serialize tx extra field: " << e.what());
return false;
}
sorted_tx_extra = std::vector<uint8_t>(oss_str.begin(), oss_str.end());
std::string extrastr = ar.str();
sorted_tx_extra = std::vector<uint8_t>(extrastr.begin(), extrastr.end());
return true;
}
//---------------------------------------------------------------
@ -721,17 +635,17 @@ namespace cryptonote
return get_additional_tx_pub_keys_from_extra(tx.extra);
}
//---------------------------------------------------------------
static bool add_tx_extra_field_to_tx_extra(std::vector<uint8_t>& tx_extra, tx_extra_field &field)
static bool add_tx_extra_field_to_tx_extra(std::vector<uint8_t>& tx_extra, tx_extra_field& field)
{
std::ostringstream oss;
binary_archive<true> ar(oss);
if (!::do_serialize(ar, field))
std::string tx_extra_str;
try {
tx_extra_str = serialization::dump_binary(field);
} catch (...) {
return false;
}
std::string tx_extra_str = oss.str();
size_t pos = tx_extra.size();
tx_extra.resize(tx_extra.size() + tx_extra_str.size());
memcpy(&tx_extra[pos], tx_extra_str.data(), tx_extra_str.size());
tx_extra.reserve(tx_extra.size() + tx_extra_str.size());
tx_extra.insert(tx_extra.end(), tx_extra_str.begin(), tx_extra_str.end());
return true;
}
@ -747,16 +661,10 @@ namespace cryptonote
bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce)
{
CHECK_AND_ASSERT_MES(extra_nonce.size() <= TX_EXTRA_NONCE_MAX_COUNT, false, "extra nonce could be 255 bytes max");
size_t start_pos = tx_extra.size();
tx_extra.resize(tx_extra.size() + 2 + extra_nonce.size());
//write tag
tx_extra[start_pos] = TX_EXTRA_NONCE;
//write len
++start_pos;
tx_extra[start_pos] = static_cast<uint8_t>(extra_nonce.size());
//write data
++start_pos;
memcpy(&tx_extra[start_pos], extra_nonce.data(), extra_nonce.size());
tx_extra.reserve(tx_extra.size() + 2 + extra_nonce.size());
tx_extra.push_back(TX_EXTRA_NONCE); // write tag
tx_extra.push_back(static_cast<uint8_t>(extra_nonce.size())); // write len
std::copy(extra_nonce.begin(), extra_nonce.end(), std::back_inserter(tx_extra));
return true;
}
@ -963,31 +871,30 @@ namespace cryptonote
add_tx_extra_field_to_tx_extra(tx_extra, field);
}
//---------------------------------------------------------------
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const size_t variant_index)
{
if (tx_extra.empty())
return true;
BINARY_ARCHIVE_STREAM(iss, tx_extra);
binary_archive<false> ar(iss);
std::ostringstream oss;
binary_archive<true> newar(oss);
bool eof = false;
while (!eof)
{
tx_extra_field field;
bool r = ::do_serialize(ar, field);
CHECK_AND_NO_ASSERT_MES_L1(r, false, "failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
if (field.type() != type)
::do_serialize(newar, field);
serialization::binary_string_unarchiver ar{tx_extra};
serialization::binary_string_archiver newar;
std::ios_base::iostate state = iss.rdstate();
eof = (EOF == iss.peek());
iss.clear(state);
try {
do
{
tx_extra_field field;
value(ar, field);
if (field.index() != variant_index)
value(newar, field);
} while (ar.remaining_bytes() > 0);
} catch (const std::exception& e) {
LOG_PRINT_L1(__func__ << ": failed to deserialize extra field: " << e.what() << "; extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
return false;
}
CHECK_AND_NO_ASSERT_MES_L1(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << lokimq::to_hex(tx_extra.begin(), tx_extra.end()));
std::string s = newar.str();
tx_extra.clear();
std::string s = oss.str();
tx_extra.reserve(s.size());
std::copy(s.begin(), s.end(), std::back_inserter(tx_extra));
return true;
@ -1224,12 +1131,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
void get_blob_hash(const epee::span<const char>& blob, crypto::hash& res)
{
cn_fast_hash(blob.data(), blob.size(), res);
}
//---------------------------------------------------------------
void get_blob_hash(const blobdata& blob, crypto::hash& res)
void get_blob_hash(const std::string_view blob, crypto::hash& res)
{
cn_fast_hash(blob.data(), blob.size(), res);
}
@ -1356,16 +1258,9 @@ namespace cryptonote
return buf;
}
//---------------------------------------------------------------
crypto::hash get_blob_hash(const blobdata& blob)
crypto::hash get_blob_hash(const std::string_view blob)
{
crypto::hash h = null_hash;
get_blob_hash(blob, h);
return h;
}
//---------------------------------------------------------------
crypto::hash get_blob_hash(const epee::span<const char>& blob)
{
crypto::hash h = null_hash;
crypto::hash h;
get_blob_hash(blob, h);
return h;
}
@ -1383,7 +1278,7 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL);
}
//---------------------------------------------------------------
bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res)
[[nodiscard]] bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res)
{
if (t.version == txversion::v1)
return false;
@ -1391,19 +1286,22 @@ namespace cryptonote
if (blob && unprunable_size)
{
CHECK_AND_ASSERT_MES(unprunable_size <= blob->size(), false, "Inconsistent transaction unprunable and blob sizes");
cryptonote::get_blob_hash(epee::span<const char>(blob->data() + unprunable_size, blob->size() - unprunable_size), res);
cryptonote::get_blob_hash(std::string_view{*blob}.substr(unprunable_size), res);
}
else
{
transaction &tt = const_cast<transaction&>(t);
std::stringstream ss;
binary_archive<true> ba(ss);
serialization::binary_string_archiver ba;
const size_t inputs = t.vin.size();
const size_t outputs = t.vout.size();
const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(t.vin[0]).key_offsets.size() - 1 : 0;
bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable");
cryptonote::get_blob_hash(ss.str(), res);
try {
tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin);
} catch (const std::exception& e) {
LOG_ERROR("Failed to serialize rct signatures (prunable): " << e.what());
return false;
}
cryptonote::get_blob_hash(ba.str(), res);
}
return true;
}
@ -1418,7 +1316,8 @@ namespace cryptonote
crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash)
{
// v1 transactions hash the entire blob
CHECK_AND_ASSERT_THROW_MES(t.version >= txversion::v2_ringct, "Hash for pruned v1 tx cannot be calculated");
if (t.version < txversion::v2_ringct)
throw std::runtime_error("Hash for pruned v1 tx cannot be calculated");
// v2 transactions hash different parts together, than hash the set of those hashes
crypto::hash hashes[3];
@ -1430,13 +1329,11 @@ namespace cryptonote
// base rct
{
std::stringstream ss;
binary_archive<true> ba(ss);
serialization::binary_string_archiver ba;
const size_t inputs = t.vin.size();
const size_t outputs = t.vout.size();
bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs);
CHECK_AND_ASSERT_THROW_MES(r, "Failed to serialize rct signatures base");
cryptonote::get_blob_hash(ss.str(), hashes[1]);
tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs); // throws on error (good)
cryptonote::get_blob_hash(ba.str(), hashes[1]);
}
// prunable rct
@ -1477,16 +1374,19 @@ namespace cryptonote
// base rct
CHECK_AND_ASSERT_MES(prefix_size <= unprunable_size && unprunable_size <= blob.size(), false, "Inconsistent transaction prefix, unprunable and blob sizes in: " << __func__);
cryptonote::get_blob_hash(epee::span<const char>(blob.data() + prefix_size, unprunable_size - prefix_size), hashes[1]);
cryptonote::get_blob_hash(std::string_view{blob}.substr(prefix_size, unprunable_size - prefix_size), hashes[1]);
}
else
{
transaction &tt = const_cast<transaction&>(t);
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = tt.rct_signatures.serialize_rctsig_base(ba, t.vin.size(), t.vout.size());
CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base");
cryptonote::get_blob_hash(ss.str(), hashes[1]);
serialization::binary_string_archiver ba;
try {
tt.rct_signatures.serialize_rctsig_base(ba, t.vin.size(), t.vout.size());
} catch (const std::exception& e) {
LOG_ERROR("Failed to serialize rct signatures base: " << e.what());
return false;
}
cryptonote::get_blob_hash(ba.str(), hashes[1]);
}
// prunable rct
@ -1494,9 +1394,10 @@ namespace cryptonote
{
hashes[2] = crypto::null_hash;
}
else
else if (!calculate_transaction_prunable_hash(t, &blob, hashes[2]))
{
CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, &blob, hashes[2]), false, "Failed to get tx prunable hash");
LOG_ERROR("Failed to get tx prunable hash");
return false;
}
// the tx hash is the hash of the 3 hashes
@ -1533,23 +1434,18 @@ namespace cryptonote
}
portions_left -= portion;
}
size_t size = addresses.size() * (sizeof(cryptonote::account_public_address) + sizeof(uint64_t)) + sizeof(uint64_t) + sizeof(uint64_t);
char* buffer = new char[size];
char* buffer_iter = buffer;
memcpy(buffer_iter, &operator_portions, sizeof(operator_portions));
buffer_iter += sizeof(operator_portions);
size_t size = sizeof(uint64_t) + addresses.size() * (sizeof(cryptonote::account_public_address) + sizeof(uint64_t)) + sizeof(uint64_t);
std::string buffer;
buffer.reserve(size);
buffer += tools::view_guts(operator_portions);
for (size_t i = 0; i < addresses.size(); i++)
{
memcpy(buffer_iter, &addresses[i], sizeof(cryptonote::account_public_address));
buffer_iter += sizeof(cryptonote::account_public_address);
memcpy(buffer_iter, &portions[i], sizeof(uint64_t));
buffer_iter += sizeof(uint64_t);
buffer += tools::view_guts(addresses[i]);
buffer += tools::view_guts(portions[i]);
}
memcpy(buffer_iter, &expiration_timestamp, sizeof(expiration_timestamp));
buffer_iter += sizeof(expiration_timestamp);
assert(buffer + size == buffer_iter);
crypto::cn_fast_hash(buffer, size, hash);
delete[] buffer;
buffer += tools::view_guts(expiration_timestamp);
assert(buffer.size() == size);
crypto::cn_fast_hash(buffer.data(), buffer.size(), hash);
return true;
}
//---------------------------------------------------------------
@ -1654,13 +1550,15 @@ namespace cryptonote
return res;
}
//---------------------------------------------------------------
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash)
[[nodiscard]] bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b, crypto::hash* block_hash)
{
std::stringstream ss;
ss << b_blob;
binary_archive<false> ba(ss);
bool r = ::serialization::serialize(ba, b);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
serialization::binary_string_unarchiver ba{b_blob};
try {
serialization::serialize(ba, b);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse block from blob: " << e.what());
return false;
}
b.invalidate_hashes();
b.miner_tx.invalidate_hashes();
if (block_hash)
@ -1673,12 +1571,12 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b)
{
return parse_and_validate_block_from_blob(b_blob, b, NULL);
return parse_and_validate_block_from_blob(b_blob, b, nullptr);
}
//---------------------------------------------------------------
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash)
bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b, crypto::hash& block_hash)
{
return parse_and_validate_block_from_blob(b_blob, b, &block_hash);
}

View File

@ -37,6 +37,7 @@
#include "include_base_utils.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "serialization/binary_utils.h"
#include <unordered_map>
namespace epee
@ -48,6 +49,8 @@ namespace service_nodes { struct quorum_vote_t; }
namespace cryptonote
{
using namespace std::literals;
struct tx_verification_context;
struct vote_verification_context;
//---------------------------------------------------------------
@ -55,13 +58,12 @@ namespace cryptonote
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx, hw::device &hwdev);
void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h);
crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx);
bool parse_and_validate_tx_prefix_from_blob(const blobdata& tx_blob, transaction_prefix& tx);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash);
bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx);
bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx);
bool is_v1_tx(const blobdata_ref& tx_blob);
bool is_v1_tx(const blobdata& tx_blob);
bool parse_and_validate_tx_prefix_from_blob(const std::string_view tx_blob, transaction_prefix& tx);
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash);
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx, crypto::hash& tx_hash);
bool parse_and_validate_tx_from_blob(const std::string_view tx_blob, transaction& tx);
bool parse_and_validate_tx_base_from_blob(const std::string_view tx_blob, transaction& tx);
bool is_v1_tx(const std::string_view tx_blob);
// skip_fields: How many fields of type <T> to skip
template<typename T>
@ -86,7 +88,7 @@ namespace cryptonote
}
bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t> &sorted_tx_extra, bool allow_partial = false);
bool sort_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<uint8_t>& sorted_tx_extra);
crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index = 0);
crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx, size_t pk_index = 0);
crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index = 0);
@ -141,10 +143,8 @@ namespace cryptonote
uint64_t get_tx_miner_fee(const transaction& tx, bool burning_enabled);
bool generate_key_image_helper(const account_keys& ack, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector<crypto::public_key>& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev);
void get_blob_hash(const blobdata& blob, crypto::hash& res);
void get_blob_hash(const epee::span<const char>& blob, crypto::hash& res);
crypto::hash get_blob_hash(const blobdata& blob);
crypto::hash get_blob_hash(const epee::span<const char>& blob);
void get_blob_hash(const std::string_view blob, crypto::hash& res);
crypto::hash get_blob_hash(const std::string_view blob);
std::string short_hash_str(const crypto::hash& h);
bool get_registration_hash(const std::vector<cryptonote::account_public_address>& addresses, uint64_t operator_portions, const std::vector<uint64_t>& portions, uint64_t expiration_timestamp, crypto::hash& hash);
@ -162,9 +162,9 @@ namespace cryptonote
bool calculate_block_hash(const block& b, crypto::hash& res);
bool get_block_hash(const block& b, crypto::hash& res);
crypto::hash get_block_hash(const block& b);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash);
bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b, crypto::hash *block_hash);
bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b);
bool parse_and_validate_block_from_blob(const std::string_view b_blob, block& b, crypto::hash &block_hash);
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
uint64_t get_outs_money_amount(const transaction& tx);
bool check_inputs_types_supported(const transaction& tx);
@ -195,52 +195,55 @@ namespace cryptonote
}
//---------------------------------------------------------------
template<class t_object>
bool t_serializable_object_from_blob(t_object& to, const blobdata& b_blob)
template <typename T>
bool t_serializable_object_from_blob(T& to, const blobdata& blob)
{
std::stringstream ss;
ss << b_blob;
binary_archive<false> ba(ss);
bool r = ::serialization::serialize(ba, to);
return r;
try {
serialization::parse_binary(blob, to);
return true;
} catch (...) {
return false;
}
}
//---------------------------------------------------------------
template<class t_object>
bool t_serializable_object_to_blob(const t_object& to, blobdata& b_blob)
template <typename T>
bool t_serializable_object_to_blob(T& val, blobdata& blob)
{
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = ::serialization::serialize(ba, const_cast<t_object&>(to));
b_blob = ss.str();
return r;
try {
blob = serialization::dump_binary(const_cast<std::remove_const_t<T>&>(val));
return true;
} catch (...) {
return false;
}
}
//---------------------------------------------------------------
template<class t_object>
blobdata t_serializable_object_to_blob(const t_object& to)
template <typename T>
blobdata t_serializable_object_to_blob(const T& val)
{
blobdata b;
t_serializable_object_to_blob(to, b);
t_serializable_object_to_blob(val, b);
return b;
}
//---------------------------------------------------------------
template<class t_object>
bool get_object_hash(const t_object& o, crypto::hash& res)
template <typename T>
bool get_object_hash(const T& o, crypto::hash& res)
{
get_blob_hash(t_serializable_object_to_blob(o), res);
return true;
}
//---------------------------------------------------------------
template<class t_object>
size_t get_object_blobsize(const t_object& o)
template <typename T>
size_t get_object_blobsize(const T& o)
{
blobdata b = t_serializable_object_to_blob(o);
return b.size();
return t_serializable_object_to_blob(o).size();
}
//---------------------------------------------------------------
template<class t_object>
bool get_object_hash(const t_object& o, crypto::hash& res, size_t& blob_size)
template <typename T>
bool get_object_hash(const T& o, crypto::hash& res, size_t& blob_size)
{
blobdata bl = t_serializable_object_to_blob(o);
blobdata bl;
if (!t_serializable_object_to_blob(o, bl))
return false;
blob_size = bl.size();
get_blob_hash(bl, res);
return true;
@ -249,10 +252,14 @@ namespace cryptonote
template <typename T>
std::string obj_to_json_str(T& obj)
{
std::stringstream ss;
json_archive<true> ar(ss, true);
bool r = ::serialization::serialize(ar, obj);
CHECK_AND_ASSERT_MES(r, "", "obj_to_json_str failed: serialization::serialize returned false");
std::ostringstream ss;
serialization::json_archiver ar{ss, true /*indent*/};
try {
serialize(ar, obj);
} catch (const std::exception& e) {
LOG_ERROR("obj_to_json_str failed: serialization failed: " << e.what());
return ""s;
}
return ss.str();
}
//---------------------------------------------------------------

View File

@ -32,6 +32,7 @@
#include "serialization/serialization.h"
#include "serialization/binary_archive.h"
#include "serialization/binary_utils.h"
#include "serialization/variant.h"
#include "crypto/crypto.h"
#include <boost/variant.hpp>
@ -167,50 +168,33 @@ namespace cryptonote
struct tx_extra_padding
{
size_t size;
// load
template <template <bool> class Archive>
bool do_serialize(Archive<false>& ar)
{
// size - 1 - because of variant tag
for (size = 1; size <= TX_EXTRA_PADDING_MAX_COUNT; ++size)
{
std::ios_base::iostate state = ar.stream().rdstate();
bool eof = EOF == ar.stream().peek();
ar.stream().clear(state);
if (eof)
break;
uint8_t zero;
if (!::do_serialize(ar, zero))
return false;
if (0 != zero)
return false;
}
return size <= TX_EXTRA_PADDING_MAX_COUNT;
}
// store
template <template <bool> class Archive>
bool do_serialize(Archive<true>& ar)
{
if(TX_EXTRA_PADDING_MAX_COUNT < size)
return false;
// i = 1 - because of variant tag
for (size_t i = 1; i < size; ++i)
{
uint8_t zero = 0;
if (!::do_serialize(ar, zero))
return false;
}
return true;
}
};
template <class Archive>
void serialize_value(Archive& ar, tx_extra_padding& pad)
{
size_t remaining;
if constexpr (Archive::is_deserializer)
remaining = ar.remaining_bytes();
else if (pad.size <= 1)
return;
else
remaining = pad.size - 1; // - 1 here (and just below) because we consider the 0x00 variant tag part of the padding
if (remaining > TX_EXTRA_PADDING_MAX_COUNT - 1) // - 1 as above.
throw std::invalid_argument{"tx_extra_padding size is larger than maximum allowed"};
char buf[TX_EXTRA_PADDING_MAX_COUNT - 1] = {};
ar.serialize_blob(buf, remaining);
if (Archive::is_deserializer)
{
if (std::string_view{buf, remaining}.find_first_not_of('\0') != std::string::npos)
throw std::invalid_argument{"Invalid non-0 padding byte"};
pad.size = remaining + 1;
}
}
struct tx_extra_pub_key
{
crypto::public_key pub_key;
@ -226,58 +210,49 @@ namespace cryptonote
BEGIN_SERIALIZE()
FIELD(nonce)
if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size()) return false;
if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size())
throw std::invalid_argument{"invalid extra nonce: too long"};
END_SERIALIZE()
};
struct tx_extra_merge_mining_tag
{
struct serialize_helper
{
tx_extra_merge_mining_tag& mm_tag;
serialize_helper(tx_extra_merge_mining_tag& mm_tag_) : mm_tag(mm_tag_)
{
}
BEGIN_SERIALIZE()
VARINT_FIELD_N("depth", mm_tag.depth)
FIELD_N("merkle_root", mm_tag.merkle_root)
END_SERIALIZE()
};
size_t depth;
crypto::hash merkle_root;
// load
template <template <bool> class Archive>
bool do_serialize(Archive<false>& ar)
{
std::string field;
if(!::do_serialize(ar, field))
return false;
std::istringstream iss(field);
binary_archive<false> iar(iss);
serialize_helper helper(*this);
return ::serialization::serialize(iar, helper);
}
// store
template <template <bool> class Archive>
bool do_serialize(Archive<true>& ar)
{
std::ostringstream oss;
binary_archive<true> oar(oss);
serialize_helper helper(*this);
if(!::do_serialize(oar, helper))
return false;
std::string field = oss.str();
return ::serialization::serialize(ar, field);
}
};
template <class Archive>
void inner_serializer(Archive& ar, tx_extra_merge_mining_tag& mm)
{
field_varint(ar, "depth", mm.depth);
field(ar, "merkle_root", mm.merkle_root);
}
// load
template <class Archive, std::enable_if_t<Archive::is_deserializer, int> = 0>
void serialize_value(Archive& ar, tx_extra_merge_mining_tag& mm)
{
// MM tag gets binary-serialized into a string, and then that string gets serialized (as a
// string). This is very strange.
std::string field;
value(ar, field);
serialization::binary_string_unarchiver inner_ar{field};
inner_serializer(inner_ar, mm);
}
// store
template <class Archive, std::enable_if_t<Archive::is_serializer, int> = 0>
void serialize_value(Archive& ar, tx_extra_merge_mining_tag& mm)
{
// As above: first we binary-serialize into a string, then we serialize the string.
serialization::binary_string_archiver inner_ar;
inner_serializer(inner_ar, mm);
std::string field = inner_ar.str();
value(ar, field);
}
// per-output additional tx pubkey for multi-destination transfers involving at least one subaddress
struct tx_extra_additional_pub_keys
{
@ -560,43 +535,48 @@ namespace cryptonote
// varint tag;
// varint size;
// varint data[];
typedef boost::variant<tx_extra_padding,
tx_extra_pub_key,
tx_extra_nonce,
tx_extra_merge_mining_tag,
tx_extra_additional_pub_keys,
tx_extra_mysterious_minergate,
tx_extra_service_node_pubkey,
tx_extra_service_node_register,
tx_extra_service_node_contributor,
tx_extra_service_node_winner,
tx_extra_service_node_state_change,
tx_extra_service_node_deregister_old,
tx_extra_tx_secret_key,
tx_extra_tx_key_image_proofs,
tx_extra_tx_key_image_unlock,
tx_extra_burn,
tx_extra_loki_name_system
> tx_extra_field;
//
// Note that the order of fields here also determines the tx extra sort order. You should not
// change the relative orders of existing tags, but new tags can be added wherever seems
// appropriate.
using tx_extra_field = boost::variant<
tx_extra_pub_key,
tx_extra_service_node_winner,
tx_extra_additional_pub_keys,
tx_extra_nonce,
tx_extra_service_node_register,
tx_extra_service_node_deregister_old,
tx_extra_service_node_state_change,
tx_extra_service_node_contributor,
tx_extra_service_node_pubkey,
tx_extra_tx_secret_key,
tx_extra_loki_name_system,
tx_extra_tx_key_image_proofs,
tx_extra_tx_key_image_unlock,
tx_extra_burn,
tx_extra_merge_mining_tag,
tx_extra_mysterious_minergate,
tx_extra_padding
>;
}
BLOB_SERIALIZER(cryptonote::tx_extra_service_node_deregister_old::vote);
BLOB_SERIALIZER(cryptonote::tx_extra_tx_key_image_proofs::proof);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_state_change, TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_deregister_old, TX_EXTRA_TAG_SERVICE_NODE_DEREG_OLD);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_winner, TX_EXTRA_TAG_SERVICE_NODE_WINNER);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_service_node_pubkey, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_secret_key, TX_EXTRA_TAG_TX_SECRET_KEY);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_burn, TX_EXTRA_TAG_BURN);
VARIANT_TAG(binary_archive, cryptonote::tx_extra_loki_name_system, TX_EXTRA_TAG_LOKI_NAME_SYSTEM);
BINARY_VARIANT_TAG(cryptonote::tx_extra_padding, TX_EXTRA_TAG_PADDING);
BINARY_VARIANT_TAG(cryptonote::tx_extra_pub_key, TX_EXTRA_TAG_PUBKEY);
BINARY_VARIANT_TAG(cryptonote::tx_extra_nonce, TX_EXTRA_NONCE);
BINARY_VARIANT_TAG(cryptonote::tx_extra_merge_mining_tag, TX_EXTRA_MERGE_MINING_TAG);
BINARY_VARIANT_TAG(cryptonote::tx_extra_additional_pub_keys, TX_EXTRA_TAG_ADDITIONAL_PUBKEYS);
BINARY_VARIANT_TAG(cryptonote::tx_extra_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_register, TX_EXTRA_TAG_SERVICE_NODE_REGISTER);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_state_change, TX_EXTRA_TAG_SERVICE_NODE_STATE_CHANGE);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_deregister_old, TX_EXTRA_TAG_SERVICE_NODE_DEREG_OLD);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_contributor, TX_EXTRA_TAG_SERVICE_NODE_CONTRIBUTOR);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_winner, TX_EXTRA_TAG_SERVICE_NODE_WINNER);
BINARY_VARIANT_TAG(cryptonote::tx_extra_service_node_pubkey, TX_EXTRA_TAG_SERVICE_NODE_PUBKEY);
BINARY_VARIANT_TAG(cryptonote::tx_extra_tx_secret_key, TX_EXTRA_TAG_TX_SECRET_KEY);
BINARY_VARIANT_TAG(cryptonote::tx_extra_tx_key_image_proofs, TX_EXTRA_TAG_TX_KEY_IMAGE_PROOFS);
BINARY_VARIANT_TAG(cryptonote::tx_extra_tx_key_image_unlock, TX_EXTRA_TAG_TX_KEY_IMAGE_UNLOCK);
BINARY_VARIANT_TAG(cryptonote::tx_extra_burn, TX_EXTRA_TAG_BURN);
BINARY_VARIANT_TAG(cryptonote::tx_extra_loki_name_system, TX_EXTRA_TAG_LOKI_NAME_SYSTEM);

View File

@ -133,7 +133,7 @@ namespace cryptonote
FIELD(multisig_kLRki)
if (real_output >= outputs.size())
return false;
throw std::invalid_argument{"invalid real_output size"};
END_SERIALIZE()
};

View File

@ -1894,11 +1894,14 @@ namespace service_nodes
m_transient.cache_data_blob.clear();
if (m_transient.state_added_to_archive)
{
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = ::serialization::serialize(ba, m_transient.cache_long_term_data);
CHECK_AND_ASSERT_MES(r, false, "Failed to store service node info: failed to serialize long term data");
m_transient.cache_data_blob.append(ss.str());
serialization::binary_string_archiver ba;
try {
serialization::serialize(ba, m_transient.cache_long_term_data);
} catch (const std::exception& e) {
LOG_ERROR("Failed to store service node info: failed to serialize long term data: " << e.what());
return false;
}
m_transient.cache_data_blob.append(ba.str());
{
auto &db = m_blockchain.get_db();
cryptonote::db_wtxn_guard txn_guard{db};
@ -1908,11 +1911,14 @@ namespace service_nodes
m_transient.cache_data_blob.clear();
{
std::stringstream ss;
binary_archive<true> ba(ss);
bool r = ::serialization::serialize(ba, m_transient.cache_short_term_data);
CHECK_AND_ASSERT_MES(r, false, "Failed to store service node info: failed to serialize short term data data");
m_transient.cache_data_blob.append(ss.str());
serialization::binary_string_archiver ba;
try {
serialization::serialize(ba, m_transient.cache_short_term_data);
} catch (const std::exception& e) {
LOG_ERROR("Failed to store service node info: failed to serialize short term data: " << e.what());
return false;
}
m_transient.cache_data_blob.append(ba.str());
{
auto &db = m_blockchain.get_db();
cryptonote::db_wtxn_guard txn_guard{db};
@ -2301,13 +2307,14 @@ namespace service_nodes
if (db.get_service_node_data(blob, true /*long_term*/))
{
bytes_loaded += blob.size();
std::stringstream ss;
ss << blob;
blob.clear();
binary_archive<false> ba(ss);
data_for_serialization data_in = {};
if (::serialization::serialize(ba, data_in) && data_in.states.size())
bool success = false;
try {
serialization::parse_binary(blob, data_in);
success = true;
} catch (...) {}
if (success && data_in.states.size())
{
// NOTE: Previously the quorum for the next state is derived from the
// state that's been updated from the next block. This is fixed in
@ -2373,13 +2380,13 @@ namespace service_nodes
return false;
bytes_loaded += blob.size();
std::stringstream ss;
ss << blob;
binary_archive<false> ba(ss);
data_for_serialization data_in = {};
bool deserialized = ::serialization::serialize(ba, data_in);
CHECK_AND_ASSERT_MES(deserialized, false, "Failed to parse service node data from blob");
try {
serialization::parse_binary(blob, data_in);
} catch (const std::exception& e) {
LOG_ERROR("Failed to parse service node data from blob: " << e.what());
return false;
}
if (data_in.states.empty())
return false;

View File

@ -239,7 +239,7 @@ namespace service_nodes
BEGIN_SERIALIZE_OBJECT()
FIELD(pubkey)
if (!W)
if (Archive::is_deserializer)
info = std::make_shared<service_node_info>();
FIELD_N("info", const_cast<service_node_info &>(*info))
END_SERIALIZE()

View File

@ -65,28 +65,22 @@ namespace protocol{
};
template<typename T>
bool cn_deserialize(const void * buff, size_t len, T & dst){
std::stringstream ss;
ss.write(static_cast<const char *>(buff), len); //ss << tx_blob;
binary_archive<false> ba(ss);
bool r = ::serialization::serialize(ba, dst);
return r;
}
template<typename T>
bool cn_deserialize(const std::string & str, T & dst){
return cn_deserialize(str.data(), str.size(), dst);
bool cn_deserialize(const std::string_view buff, T& dst) {
try {
serialization::parse_binary(buff, dst);
return true;
} catch (...) {
return false;
}
}
template<typename T>
std::string cn_serialize(T & obj){
std::ostringstream oss;
binary_archive<true> oar(oss);
bool success = ::serialization::serialize(oar, obj);
if (!success){
try {
return serialization::dump_binary(obj);
} catch (...) {
throw exc::EncodingException("Could not CN serialize given object");
}
return oss.str();
}
// Crypto / encryption

View File

@ -33,6 +33,7 @@
#include "misc_log_ex.h"
#include "span.h"
#include "common/perf_timer.h"
#include "common/varint.h"
#include "cryptonote_config.h"
extern "C"
{

View File

@ -412,15 +412,17 @@ namespace rct {
hashes.push_back(rv.message);
crypto::hash h;
std::stringstream ss;
binary_archive<true> ba(ss);
CHECK_AND_ASSERT_THROW_MES(!rv.mixRing.empty(), "Empty mixRing");
const size_t inputs = is_rct_simple(rv.type) ? rv.mixRing.size() : rv.mixRing[0].size();
const size_t outputs = rv.ecdhInfo.size();
key prehash;
CHECK_AND_ASSERT_THROW_MES(const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs),
"Failed to serialize rctSigBase");
cryptonote::get_blob_hash(ss.str(), h);
std::string blob;
{
serialization::binary_string_archiver ba;
const_cast<rctSig&>(rv).serialize_rctsig_base(ba, inputs, outputs);
blob = ba.str();
}
cryptonote::get_blob_hash(blob, h);
hashes.push_back(hash2rct(h));
keyV kv;
@ -461,7 +463,7 @@ namespace rct {
}
}
hashes.push_back(cn_fast_hash(kv));
hwdev.mlsag_prehash(ss.str(), inputs, outputs, hashes, rv.outPk, prehash);
hwdev.mlsag_prehash(blob, inputs, outputs, hashes, rv.outPk, prehash);
return prehash;
}

View File

@ -68,6 +68,9 @@ extern "C" {
//Namespace specifically for ring ct code
namespace rct {
using namespace std::literals;
//basic ops containers
typedef unsigned char * Bytes;
@ -209,7 +212,7 @@ namespace rct {
FIELD(t)
if (L.empty() || L.size() != R.size())
return false;
throw std::runtime_error("Bad bulletproof serialization");
END_SERIALIZE()
};
@ -218,6 +221,16 @@ namespace rct {
size_t n_bulletproof_amounts(const std::vector<Bulletproof> &proofs);
size_t n_bulletproof_max_amounts(const std::vector<Bulletproof> &proofs);
template <typename Archive, typename T>
auto start_array(Archive& ar, std::string_view tag, std::vector<T>& v, size_t size) {
ar.tag(tag);
if (Archive::is_deserializer)
v.resize(size);
else if (v.size() != size)
throw std::invalid_argument{"invalid "s + std::string{tag} + " size"s};
return ar.begin_array();
}
//A container to hold all signatures necessary for RingCT
// rangeSigs holds all the rangeproof data of a transaction
// MG holds the MLSAG signature of a transaction
@ -247,72 +260,48 @@ namespace rct {
ctkeyV outPk;
xmr_amount txnFee; // contains b
template<bool W, template <bool> class Archive>
bool serialize_rctsig_base(Archive<W> &ar, size_t inputs, size_t outputs)
template <typename Archive>
void serialize_rctsig_base(Archive &ar, size_t inputs, size_t outputs)
{
FIELD(type)
field(ar, "type", type);
if (type == RCTTypeNull)
return ar.stream().good();
return;
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
return false;
VARINT_FIELD(txnFee)
throw std::invalid_argument{"invalid ringct type"};
field_varint(ar, "txnFee", txnFee);
// inputs/outputs not saved, only here for serialization help
// FIELD(message) - not serialized, it can be reconstructed
// FIELD(mixRing) - not serialized, it can be reconstructed
if (type == RCTTypeSimple) // moved to prunable with bulletproofs
{
ar.tag("pseudoOuts");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
if (pseudoOuts.size() != inputs)
return false;
for (size_t i = 0; i < inputs; ++i)
{
FIELDS(pseudoOuts[i])
if (inputs - i > 1)
ar.delimit_array();
}
ar.end_array();
auto arr = start_array(ar, "pseudoOuts", pseudoOuts, inputs);
for (auto& e : pseudoOuts)
value(arr.element(), e);
}
ar.tag("ecdhInfo");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo);
if (ecdhInfo.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
{
auto arr = start_array(ar, "ecdhInfo", ecdhInfo, outputs);
if (type == RCTTypeBulletproof2)
{
ar.begin_object();
if (!typename Archive<W>::is_saving())
memset(ecdhInfo[i].amount.bytes, 0, sizeof(ecdhInfo[i].amount.bytes));
crypto::hash8 &amount = (crypto::hash8&)ecdhInfo[i].amount;
FIELD(amount);
ar.end_object();
for (auto& e : ecdhInfo) {
auto obj = arr.element().begin_object();
if (Archive::is_deserializer)
memset(e.amount.bytes, 0, sizeof(e.amount.bytes));
field(ar, "amount", reinterpret_cast<crypto::hash8&>(e.amount));
}
} else {
for (auto& e : ecdhInfo)
value(arr.element(), e);
}
else
{
FIELDS(ecdhInfo[i])
}
if (outputs - i > 1)
ar.delimit_array();
}
ar.end_array();
ar.tag("outPk");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk);
if (outPk.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
{
FIELDS(outPk[i].mask)
if (outputs - i > 1)
ar.delimit_array();
auto arr = start_array(ar, "outPk", outPk, outputs);
for (auto& e : outPk)
value(arr.element(), e.mask);
}
ar.end_array();
return ar.stream().good();
}
};
struct rctSigPrunable {
@ -322,115 +311,80 @@ namespace rct {
keyV pseudoOuts; //C - for simple rct
// when changing this function, update cryptonote::get_pruned_transaction_weight
template<bool W, template <bool> class Archive>
bool serialize_rctsig_prunable(Archive<W> &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
template<typename Archive>
void serialize_rctsig_prunable(Archive &ar, uint8_t type, size_t inputs, size_t outputs, size_t mixin)
{
if (type == RCTTypeNull)
return ar.stream().good();
return;
if (type != RCTTypeFull && type != RCTTypeSimple && type != RCTTypeBulletproof && type != RCTTypeBulletproof2)
return false;
throw std::invalid_argument{"invalid ringct type"};
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2)
{
uint32_t nbp = bulletproofs.size();
if (type == RCTTypeBulletproof2)
VARINT_FIELD(nbp)
field_varint(ar, "nbp", nbp);
else
FIELD(nbp)
ar.tag("bp");
ar.begin_array();
field(ar, "nbp", nbp);
if (nbp > outputs)
return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs);
for (size_t i = 0; i < nbp; ++i)
{
FIELDS(bulletproofs[i])
if (nbp - i > 1)
ar.delimit_array();
}
if (n_bulletproof_max_amounts(bulletproofs) < outputs)
return false;
ar.end_array();
throw std::invalid_argument{"too many bulletproofs"};
auto arr = start_array(ar, "bp", bulletproofs, nbp);
for (auto& b : bulletproofs)
value(arr.element(), b);
if (auto n_max = n_bulletproof_max_amounts(bulletproofs); n_max < outputs)
throw std::invalid_argument{"invalid bulletproofs: n_max (" + std::to_string(n_max) + ") < outputs (" + std::to_string(outputs) + ")"};
}
else
{
ar.tag("rangeSigs");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs);
if (rangeSigs.size() != outputs)
return false;
for (size_t i = 0; i < outputs; ++i)
{
FIELDS(rangeSigs[i])
if (outputs - i > 1)
ar.delimit_array();
}
ar.end_array();
auto arr = start_array(ar, "rangeSigs", rangeSigs, outputs);
for (auto& s : rangeSigs)
value(arr.element(), s);
}
ar.tag("MGs");
ar.begin_array();
// we keep a byte for size of MGs, because we don't know whether this is
// a simple or full rct signature, and it's starting to annoy the hell out of me
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? inputs : 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
if (MGs.size() != mg_elements)
return false;
for (size_t i = 0; i < mg_elements; ++i)
{
// we save the MGs contents directly, because we want it to save its
// arrays and matrices without the size prefixes, and the load can't
// know what size to expect if it's not in the data
ar.begin_object();
ar.tag("ss");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss);
if (MGs[i].ss.size() != mixin + 1)
return false;
for (size_t j = 0; j < mixin + 1; ++j)
{
ar.begin_array();
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? 1 : inputs) + 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]);
if (MGs[i].ss[j].size() != mg_ss2_elements)
return false;
for (size_t k = 0; k < mg_ss2_elements; ++k)
{
FIELDS(MGs[i].ss[j][k])
if (mg_ss2_elements - k > 1)
ar.delimit_array();
}
ar.end_array();
if (mixin + 1 - j > 1)
ar.delimit_array();
}
ar.end_array();
ar.tag("cc");
FIELDS(MGs[i].cc)
// MGs[i].II not saved, it can be reconstructed
ar.end_object();
if (mg_elements - i > 1)
ar.delimit_array();
size_t mg_elements = 1, mg_ss2_elements = inputs + 1;
if (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) {
mg_elements = inputs;
mg_ss2_elements = 2;
}
{
auto arr = start_array(ar, "MGs", MGs, mg_elements);
for (auto& mg : MGs)
{
auto obj = arr.element().begin_object();
// we save the MGs contents directly, because we want it to save its
// arrays and matrices without the size prefixes, and the load can't
// know what size to expect if it's not in the data
{
auto arr_ss = start_array(ar, "ss", mg.ss, mixin + 1);
for (auto& ss : mg.ss)
{
auto arr_ss2 = arr_ss.element().begin_array();
if constexpr (Archive::is_deserializer)
ss.resize(mg_ss2_elements);
else if (ss.size() != mg_ss2_elements)
throw std::invalid_argument{"invalid mg_ss2 size"};
for (auto& x : ss)
value(arr_ss2.element(), x);
}
}
field(ar, "cc", mg.cc);
// MGs[i].II not saved, it can be reconstructed
}
}
ar.end_array();
if (type == RCTTypeBulletproof || type == RCTTypeBulletproof2)
{
ar.tag("pseudoOuts");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts);
if (pseudoOuts.size() != inputs)
return false;
for (size_t i = 0; i < inputs; ++i)
{
FIELDS(pseudoOuts[i])
if (inputs - i > 1)
ar.delimit_array();
}
ar.end_array();
auto arr = start_array(ar, "pseudoOuts", pseudoOuts, inputs);
for (auto& o : pseudoOuts)
value(ar, o);
}
return ar.stream().good();
}
};
@ -591,52 +545,20 @@ BLOB_SERIALIZER(rct::ctkey);
BLOB_SERIALIZER(rct::multisig_kLRki);
BLOB_SERIALIZER(rct::boroSig);
VARIANT_TAG(debug_archive, rct::key, "rct::key");
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
VARIANT_TAG(debug_archive, rct::keyV, "rct::keyV");
VARIANT_TAG(debug_archive, rct::keyM, "rct::keyM");
VARIANT_TAG(debug_archive, rct::ctkey, "rct::ctkey");
VARIANT_TAG(debug_archive, rct::ctkeyV, "rct::ctkeyV");
VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
VARIANT_TAG(debug_archive, rct::Bulletproof, "rct::bulletproof");
VARIANT_TAG(debug_archive, rct::multisig_kLRki, "rct::multisig_kLRki");
VARIANT_TAG(debug_archive, rct::multisig_out, "rct::multisig_out");
VARIANT_TAG(binary_archive, rct::key, 0x90);
VARIANT_TAG(binary_archive, rct::key64, 0x91);
VARIANT_TAG(binary_archive, rct::keyV, 0x92);
VARIANT_TAG(binary_archive, rct::keyM, 0x93);
VARIANT_TAG(binary_archive, rct::ctkey, 0x94);
VARIANT_TAG(binary_archive, rct::ctkeyV, 0x95);
VARIANT_TAG(binary_archive, rct::ctkeyM, 0x96);
VARIANT_TAG(binary_archive, rct::ecdhTuple, 0x97);
VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
VARIANT_TAG(binary_archive, rct::Bulletproof, 0x9c);
VARIANT_TAG(binary_archive, rct::multisig_kLRki, 0x9d);
VARIANT_TAG(binary_archive, rct::multisig_out, 0x9e);
VARIANT_TAG(json_archive, rct::key, "rct_key");
VARIANT_TAG(json_archive, rct::key64, "rct_key64");
VARIANT_TAG(json_archive, rct::keyV, "rct_keyV");
VARIANT_TAG(json_archive, rct::keyM, "rct_keyM");
VARIANT_TAG(json_archive, rct::ctkey, "rct_ctkey");
VARIANT_TAG(json_archive, rct::ctkeyV, "rct_ctkeyV");
VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
VARIANT_TAG(json_archive, rct::Bulletproof, "rct_bulletproof");
VARIANT_TAG(json_archive, rct::multisig_kLRki, "rct_multisig_kLR");
VARIANT_TAG(json_archive, rct::multisig_out, "rct_multisig_out");
VARIANT_TAG(rct::key, "rct_key", 0x90);
VARIANT_TAG(rct::key64, "rct_key64", 0x91);
VARIANT_TAG(rct::keyV, "rct_keyV", 0x92);
VARIANT_TAG(rct::keyM, "rct_keyM", 0x93);
VARIANT_TAG(rct::ctkey, "rct_ctkey", 0x94);
VARIANT_TAG(rct::ctkeyV, "rct_ctkeyV", 0x95);
VARIANT_TAG(rct::ctkeyM, "rct_ctkeyM", 0x96);
VARIANT_TAG(rct::ecdhTuple, "rct_ecdhTuple", 0x97);
VARIANT_TAG(rct::mgSig, "rct_mgSig", 0x98);
VARIANT_TAG(rct::rangeSig, "rct_rangeSig", 0x99);
VARIANT_TAG(rct::boroSig, "rct_boroSig", 0x9a);
VARIANT_TAG(rct::rctSig, "rct_rctSig", 0x9b);
VARIANT_TAG(rct::Bulletproof, "rct_bulletproof", 0x9c);
VARIANT_TAG(rct::multisig_kLRki, "rct_multisig_kLR", 0x9d);
VARIANT_TAG(rct::multisig_out, "rct_multisig_out", 0x9e);
#endif /* RCTTYPES_H */

View File

@ -458,8 +458,7 @@ namespace cryptonote { namespace rpc {
public:
pruned_transaction(transaction& tx) : tx(tx) {}
BEGIN_SERIALIZE_OBJECT()
bool r = tx.serialize_base(ar);
if (!r) return false;
tx.serialize_base(ar);
END_SERIALIZE()
};
//------------------------------------------------------------------------------------------------------------------------------
@ -757,15 +756,16 @@ namespace cryptonote { namespace rpc {
res.status = "Failed to parse and validate tx from blob";
return res;
}
std::stringstream ss;
binary_archive<true> ba(ss);
if (!tx.serialize_base(ba))
{
res.status = "Failed to serialize transaction base";
serialization::binary_string_archiver ba;
try {
tx.serialize_base(ba);
} catch (const std::exception& e) {
res.status = "Failed to serialize transaction base: "s + e.what();
return res;
}
const cryptonote::blobdata pruned = ss.str();
sorted_txs.emplace_back(h, pruned, get_transaction_prunable_hash(tx), std::string(ptx_it->tx_blob, pruned.size()));
std::string pruned = ba.str();
std::string pruned2{ptx_it->tx_blob, pruned.size()};
sorted_txs.emplace_back(h, std::move(pruned), get_transaction_prunable_hash(tx), std::move(pruned2));
missed_txs.erase(missed_it);
per_tx_pool_tx_info.emplace(h, *ptx_it);
++found_in_pool;

View File

@ -859,11 +859,10 @@ namespace
std::string compress_integer_array(const std::vector<T> &v)
{
std::string s;
s.resize(v.size() * (sizeof(T) * 8 / 7 + 1));
char *ptr = &s[0];
s.reserve(tools::VARINT_MAX_LENGTH<T>);
auto ins = std::back_inserter(s);
for (const T &t: v)
tools::write_varint(ptr, t);
s.resize(ptr - s.data());
tools::write_varint(ins, t);
return s;
}
@ -871,15 +870,10 @@ namespace
std::vector<T> decompress_integer_array(const std::string &s)
{
std::vector<T> v;
v.reserve(s.size());
int read = 0;
const std::string::const_iterator end = s.end();
for (std::string::const_iterator i = s.begin(); i != end; std::advance(i, read))
for (auto it = s.begin(); it < s.end(); )
{
T t;
read = tools::read_varint(std::string::const_iterator(i), s.end(), t);
CHECK_AND_ASSERT_THROW_MES(read > 0 && read <= 256, "Error decompressing data");
v.push_back(t);
int read = tools::read_varint(it, s.end(), v.emplace_back());
CHECK_AND_ASSERT_THROW_MES(read > 0, "Error decompressing data");
}
return v;
}

View File

@ -88,7 +88,7 @@ rapidjson::Value GetHeight::Response::toJson(rapidjson::Document& doc) const
void GetHeight::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
json::load_from_json_object(val, "height", height);
}
@ -98,7 +98,7 @@ rapidjson::Value GetBlocksFast::Request::toJson(rapidjson::Document& doc) const
auto& al = doc.GetAllocator();
INSERT_INTO_JSON_OBJECT(val, doc, block_ids, block_ids);
json::insert_into_json_object(val, doc, "block_ids", block_ids);
val.AddMember("start_height", start_height, al);
val.AddMember("prune", prune, al);
@ -107,9 +107,9 @@ rapidjson::Value GetBlocksFast::Request::toJson(rapidjson::Document& doc) const
void GetBlocksFast::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, prune, prune);
json::load_from_json_object(val, "block_ids", block_ids);
json::load_from_json_object(val, "start_height", start_height);
json::load_from_json_object(val, "prune", prune);
}
rapidjson::Value GetBlocksFast::Response::toJson(rapidjson::Document& doc) const
@ -118,20 +118,20 @@ rapidjson::Value GetBlocksFast::Response::toJson(rapidjson::Document& doc) const
auto& al = doc.GetAllocator();
INSERT_INTO_JSON_OBJECT(val, doc, blocks, blocks);
json::insert_into_json_object(val, doc, "blocks", blocks);
val.AddMember("start_height", start_height, al);
val.AddMember("current_height", current_height, al);
INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
json::insert_into_json_object(val, doc, "output_indices", output_indices);
return val;
}
void GetBlocksFast::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, blocks, blocks);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
json::load_from_json_object(val, "blocks", blocks);
json::load_from_json_object(val, "start_height", start_height);
json::load_from_json_object(val, "current_height", current_height);
json::load_from_json_object(val, "output_indices", output_indices);
}
@ -141,7 +141,7 @@ rapidjson::Value GetHashesFast::Request::toJson(rapidjson::Document& doc) const
auto& al = doc.GetAllocator();
INSERT_INTO_JSON_OBJECT(val, doc, known_hashes, known_hashes);
json::insert_into_json_object(val, doc, "known_hashes", known_hashes);
val.AddMember("start_height", start_height, al);
return val;
@ -149,8 +149,8 @@ rapidjson::Value GetHashesFast::Request::toJson(rapidjson::Document& doc) const
void GetHashesFast::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, known_hashes, known_hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
json::load_from_json_object(val, "known_hashes", known_hashes);
json::load_from_json_object(val, "start_height", start_height);
}
rapidjson::Value GetHashesFast::Response::toJson(rapidjson::Document& doc) const
@ -159,7 +159,7 @@ rapidjson::Value GetHashesFast::Response::toJson(rapidjson::Document& doc) const
auto& al = doc.GetAllocator();
INSERT_INTO_JSON_OBJECT(val, doc, hashes, hashes);
json::insert_into_json_object(val, doc, "hashes", hashes);
val.AddMember("start_height", start_height, al);
val.AddMember("current_height", current_height, al);
@ -168,9 +168,9 @@ rapidjson::Value GetHashesFast::Response::toJson(rapidjson::Document& doc) const
void GetHashesFast::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hashes, hashes);
GET_FROM_JSON_OBJECT(val, start_height, start_height);
GET_FROM_JSON_OBJECT(val, current_height, current_height);
json::load_from_json_object(val, "hashes", hashes);
json::load_from_json_object(val, "start_height", start_height);
json::load_from_json_object(val, "current_height", current_height);
}
@ -178,30 +178,30 @@ rapidjson::Value GetTransactions::Request::toJson(rapidjson::Document& doc) cons
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, tx_hashes, tx_hashes);
json::insert_into_json_object(val, doc, "tx_hashes", tx_hashes);
return val;
}
void GetTransactions::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_hashes, tx_hashes);
json::load_from_json_object(val, "tx_hashes", tx_hashes);
}
rapidjson::Value GetTransactions::Response::toJson(rapidjson::Document& doc) const
{
rapidjson::Value val(rapidjson::kObjectType);
INSERT_INTO_JSON_OBJECT(val, doc, txs, txs);
INSERT_INTO_JSON_OBJECT(val, doc, missed_hashes, missed_hashes);
json::insert_into_json_object(val, doc, "txs", txs);
json::insert_into_json_object(val, doc, "missed_hashes", missed_hashes);
return val;
}
void GetTransactions::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, txs, txs);
GET_FROM_JSON_OBJECT(val, missed_hashes, missed_hashes);
json::load_from_json_object(val, "txs", txs);
json::load_from_json_object(val, "missed_hashes", missed_hashes);
}
@ -209,28 +209,28 @@ rapidjson::Value KeyImagesSpent::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
json::insert_into_json_object(val, doc, "key_images", key_images);
return val;
}
void KeyImagesSpent::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, key_images, key_images);
json::load_from_json_object(val, "key_images", key_images);
}
rapidjson::Value KeyImagesSpent::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, spent_status, spent_status);
json::insert_into_json_object(val, doc, "spent_status", spent_status);
return val;
}
void KeyImagesSpent::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, spent_status, spent_status);
json::load_from_json_object(val, "spent_status", spent_status);
}
@ -238,51 +238,51 @@ rapidjson::Value GetTxGlobalOutputIndices::Request::toJson(rapidjson::Document&
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, tx_hash, tx_hash);
json::insert_into_json_object(val, doc, "tx_hash", tx_hash);
return val;
}
void GetTxGlobalOutputIndices::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_hash, tx_hash);
json::load_from_json_object(val, "tx_hash", tx_hash);
}
rapidjson::Value GetTxGlobalOutputIndices::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, output_indices, output_indices);
json::insert_into_json_object(val, doc, "output_indices", output_indices);
return val;
}
void GetTxGlobalOutputIndices::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, output_indices, output_indices);
json::load_from_json_object(val, "output_indices", output_indices);
}
rapidjson::Value SendRawTx::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, tx, tx);
INSERT_INTO_JSON_OBJECT(val, doc, relay, relay);
json::insert_into_json_object(val, doc, "tx", tx);
json::insert_into_json_object(val, doc, "relay", relay);
return val;
}
void SendRawTx::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx, tx);
GET_FROM_JSON_OBJECT(val, relay, relay);
json::load_from_json_object(val, "tx", tx);
json::load_from_json_object(val, "relay", relay);
}
rapidjson::Value SendRawTx::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, relayed, relayed);
json::insert_into_json_object(val, doc, "relayed", relayed);
return val;
}
@ -290,39 +290,39 @@ rapidjson::Value SendRawTx::Response::toJson(rapidjson::Document& doc) const
void SendRawTx::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, relayed, relayed);
json::load_from_json_object(val, "relayed", relayed);
}
rapidjson::Value SendRawTxHex::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, tx_as_hex, tx_as_hex);
INSERT_INTO_JSON_OBJECT(val, doc, relay, relay);
json::insert_into_json_object(val, doc, "tx_as_hex", tx_as_hex);
json::insert_into_json_object(val, doc, "relay", relay);
return val;
}
void SendRawTxHex::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, tx_as_hex, tx_as_hex);
GET_FROM_JSON_OBJECT(val, relay, relay);
json::load_from_json_object(val, "tx_as_hex", tx_as_hex);
json::load_from_json_object(val, "relay", relay);
}
rapidjson::Value StartMining::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, miner_address, miner_address);
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
json::insert_into_json_object(val, doc, "miner_address", miner_address);
json::insert_into_json_object(val, doc, "threads_count", threads_count);
return val;
}
void StartMining::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
json::load_from_json_object(val, "miner_address", miner_address);
json::load_from_json_object(val, "threads_count", threads_count);
}
rapidjson::Value StartMining::Response::toJson(rapidjson::Document& doc) const
@ -367,20 +367,20 @@ rapidjson::Value MiningStatus::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, active, active);
INSERT_INTO_JSON_OBJECT(val, doc, speed, speed);
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
INSERT_INTO_JSON_OBJECT(val, doc, address, address);
json::insert_into_json_object(val, doc, "active", active);
json::insert_into_json_object(val, doc, "speed", speed);
json::insert_into_json_object(val, doc, "threads_count", threads_count);
json::insert_into_json_object(val, doc, "address", address);
return val;
}
void MiningStatus::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, active, active);
GET_FROM_JSON_OBJECT(val, speed, speed);
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
GET_FROM_JSON_OBJECT(val, address, address);
json::load_from_json_object(val, "active", active);
json::load_from_json_object(val, "speed", speed);
json::load_from_json_object(val, "threads_count", threads_count);
json::load_from_json_object(val, "address", address);
}
@ -397,14 +397,14 @@ rapidjson::Value GetInfo::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, info, info);
json::insert_into_json_object(val, doc, "info", info);
return val;
}
void GetInfo::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, info, info);
json::load_from_json_object(val, "info", info);
}
@ -435,28 +435,28 @@ rapidjson::Value GetBlockHash::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, height, height);
json::insert_into_json_object(val, doc, "height", height);
return val;
}
void GetBlockHash::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
json::load_from_json_object(val, "height", height);
}
rapidjson::Value GetBlockHash::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
json::insert_into_json_object(val, doc, "hash", hash);
return val;
}
void GetBlockHash::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hash, hash);
json::load_from_json_object(val, "hash", hash);
}
@ -475,14 +475,14 @@ rapidjson::Value GetLastBlockHeader::Response::toJson(rapidjson::Document& doc)
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
json::insert_into_json_object(val, doc, "header", header);
return val;
}
void GetLastBlockHeader::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
json::load_from_json_object(val, "header", header);
}
@ -490,28 +490,28 @@ rapidjson::Value GetBlockHeaderByHash::Request::toJson(rapidjson::Document& doc)
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, hash, hash);
json::insert_into_json_object(val, doc, "hash", hash);
return val;
}
void GetBlockHeaderByHash::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, hash, hash);
json::load_from_json_object(val, "hash", hash);
}
rapidjson::Value GetBlockHeaderByHash::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
json::insert_into_json_object(val, doc, "header", header);
return val;
}
void GetBlockHeaderByHash::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
json::load_from_json_object(val, "header", header);
}
@ -519,28 +519,28 @@ rapidjson::Value GetBlockHeaderByHeight::Request::toJson(rapidjson::Document& do
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, height, height);
json::insert_into_json_object(val, doc, "height", height);
return val;
}
void GetBlockHeaderByHeight::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, height, height);
json::load_from_json_object(val, "height", height);
}
rapidjson::Value GetBlockHeaderByHeight::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, header, header);
json::insert_into_json_object(val, doc, "header", header);
return val;
}
void GetBlockHeaderByHeight::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, header, header);
json::load_from_json_object(val, "header", header);
}
@ -548,28 +548,28 @@ rapidjson::Value GetBlockHeadersByHeight::Request::toJson(rapidjson::Document& d
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, heights, heights);
json::insert_into_json_object(val, doc, "heights", heights);
return val;
}
void GetBlockHeadersByHeight::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, heights, heights);
json::load_from_json_object(val, "heights", heights);
}
rapidjson::Value GetBlockHeadersByHeight::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, headers, headers);
json::insert_into_json_object(val, doc, "headers", headers);
return val;
}
void GetBlockHeadersByHeight::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, headers, headers);
json::load_from_json_object(val, "headers", headers);
}
@ -588,16 +588,16 @@ rapidjson::Value GetPeerList::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, white_list, white_list);
INSERT_INTO_JSON_OBJECT(val, doc, gray_list, gray_list);
json::insert_into_json_object(val, doc, "white_list", white_list);
json::insert_into_json_object(val, doc, "gray_list", gray_list);
return val;
}
void GetPeerList::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, white_list, white_list);
GET_FROM_JSON_OBJECT(val, gray_list, gray_list);
json::load_from_json_object(val, "white_list", white_list);
json::load_from_json_object(val, "gray_list", gray_list);
}
@ -614,7 +614,7 @@ rapidjson::Value SetLogLevel::Request::toJson(rapidjson::Document& doc) const
void SetLogLevel::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, level, level);
json::load_from_json_object(val, "level", level);
}
rapidjson::Value SetLogLevel::Response::toJson(rapidjson::Document& doc) const
@ -640,16 +640,16 @@ rapidjson::Value GetTransactionPool::Response::toJson(rapidjson::Document& doc)
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, transactions, transactions);
INSERT_INTO_JSON_OBJECT(val, doc, key_images, key_images);
json::insert_into_json_object(val, doc, "transactions", transactions);
json::insert_into_json_object(val, doc, "key_images", key_images);
return val;
}
void GetTransactionPool::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, transactions, transactions);
GET_FROM_JSON_OBJECT(val, key_images, key_images);
json::load_from_json_object(val, "transactions", transactions);
json::load_from_json_object(val, "key_images", key_images);
}
@ -657,28 +657,28 @@ rapidjson::Value HardForkInfo::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, version, version);
json::insert_into_json_object(val, doc, "version", version);
return val;
}
void HardForkInfo::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, version, version);
json::load_from_json_object(val, "version", version);
}
rapidjson::Value HardForkInfo::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, info, info);
json::insert_into_json_object(val, doc, "info", info);
return val;
}
void HardForkInfo::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, info, info);
json::load_from_json_object(val, "info", info);
}
@ -686,36 +686,36 @@ rapidjson::Value GetOutputHistogram::Request::toJson(rapidjson::Document& doc) c
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
INSERT_INTO_JSON_OBJECT(val, doc, min_count, min_count);
INSERT_INTO_JSON_OBJECT(val, doc, max_count, max_count);
INSERT_INTO_JSON_OBJECT(val, doc, unlocked, unlocked);
INSERT_INTO_JSON_OBJECT(val, doc, recent_cutoff, recent_cutoff);
json::insert_into_json_object(val, doc, "amounts", amounts);
json::insert_into_json_object(val, doc, "min_count", min_count);
json::insert_into_json_object(val, doc, "max_count", max_count);
json::insert_into_json_object(val, doc, "unlocked", unlocked);
json::insert_into_json_object(val, doc, "recent_cutoff", recent_cutoff);
return val;
}
void GetOutputHistogram::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, min_count, min_count);
GET_FROM_JSON_OBJECT(val, max_count, max_count);
GET_FROM_JSON_OBJECT(val, unlocked, unlocked);
GET_FROM_JSON_OBJECT(val, recent_cutoff, recent_cutoff);
json::load_from_json_object(val, "amounts", amounts);
json::load_from_json_object(val, "min_count", min_count);
json::load_from_json_object(val, "max_count", max_count);
json::load_from_json_object(val, "unlocked", unlocked);
json::load_from_json_object(val, "recent_cutoff", recent_cutoff);
}
rapidjson::Value GetOutputHistogram::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, histogram, histogram);
json::insert_into_json_object(val, doc, "histogram", histogram);
return val;
}
void GetOutputHistogram::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, histogram, histogram);
json::load_from_json_object(val, "histogram", histogram);
}
@ -723,28 +723,28 @@ rapidjson::Value GetOutputKeys::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, outputs, outputs);
json::insert_into_json_object(val, doc, "outputs", outputs);
return val;
}
void GetOutputKeys::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, outputs, outputs);
json::load_from_json_object(val, "outputs", outputs);
}
rapidjson::Value GetOutputKeys::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, keys, keys);
json::insert_into_json_object(val, doc, "keys", keys);
return val;
}
void GetOutputKeys::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, keys, keys);
json::load_from_json_object(val, "keys", keys);
}
@ -761,86 +761,86 @@ rapidjson::Value GetRPCVersion::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, version, version);
json::insert_into_json_object(val, doc, "version", version);
return val;
}
void GetRPCVersion::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, version, version);
json::load_from_json_object(val, "version", version);
}
rapidjson::Value GetFeeEstimate::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, num_grace_blocks, num_grace_blocks);
json::insert_into_json_object(val, doc, "num_grace_blocks", num_grace_blocks);
return val;
}
void GetFeeEstimate::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, num_grace_blocks, num_grace_blocks);
json::load_from_json_object(val, "num_grace_blocks", num_grace_blocks);
}
rapidjson::Value GetFeeEstimate::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, estimated_base_fee_per_byte, estimated_base_fee_per_byte);
INSERT_INTO_JSON_OBJECT(val, doc, estimated_base_fee_per_output, estimated_base_fee_per_output);
INSERT_INTO_JSON_OBJECT(val, doc, fee_mask, fee_mask);
INSERT_INTO_JSON_OBJECT(val, doc, size_scale, size_scale);
INSERT_INTO_JSON_OBJECT(val, doc, hard_fork_version, hard_fork_version);
json::insert_into_json_object(val, doc, "estimated_base_fee_per_byte", estimated_base_fee_per_byte);
json::insert_into_json_object(val, doc, "estimated_base_fee_per_output", estimated_base_fee_per_output);
json::insert_into_json_object(val, doc, "fee_mask", fee_mask);
json::insert_into_json_object(val, doc, "size_scale", size_scale);
json::insert_into_json_object(val, doc, "hard_fork_version", hard_fork_version);
return val;
}
void GetFeeEstimate::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, estimated_base_fee_per_byte, estimated_base_fee_per_byte);
GET_FROM_JSON_OBJECT(val, estimated_base_fee_per_output, estimated_base_fee_per_output);
GET_FROM_JSON_OBJECT(val, fee_mask, fee_mask);
GET_FROM_JSON_OBJECT(val, size_scale, size_scale);
GET_FROM_JSON_OBJECT(val, hard_fork_version, hard_fork_version);
json::load_from_json_object(val, "estimated_base_fee_per_byte", estimated_base_fee_per_byte);
json::load_from_json_object(val, "estimated_base_fee_per_output", estimated_base_fee_per_output);
json::load_from_json_object(val, "fee_mask", fee_mask);
json::load_from_json_object(val, "size_scale", size_scale);
json::load_from_json_object(val, "hard_fork_version", hard_fork_version);
}
rapidjson::Value GetOutputDistribution::Request::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, amounts, amounts);
INSERT_INTO_JSON_OBJECT(val, doc, from_height, from_height);
INSERT_INTO_JSON_OBJECT(val, doc, to_height, to_height);
INSERT_INTO_JSON_OBJECT(val, doc, cumulative, cumulative);
json::insert_into_json_object(val, doc, "amounts", amounts);
json::insert_into_json_object(val, doc, "from_height", from_height);
json::insert_into_json_object(val, doc, "to_height", to_height);
json::insert_into_json_object(val, doc, "cumulative", cumulative);
return val;
}
void GetOutputDistribution::Request::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, amounts, amounts);
GET_FROM_JSON_OBJECT(val, from_height, from_height);
GET_FROM_JSON_OBJECT(val, to_height, to_height);
GET_FROM_JSON_OBJECT(val, cumulative, cumulative);
json::load_from_json_object(val, "amounts", amounts);
json::load_from_json_object(val, "from_height", from_height);
json::load_from_json_object(val, "to_height", to_height);
json::load_from_json_object(val, "cumulative", cumulative);
}
rapidjson::Value GetOutputDistribution::Response::toJson(rapidjson::Document& doc) const
{
auto val = Message::toJson(doc);
INSERT_INTO_JSON_OBJECT(val, doc, status, status);
INSERT_INTO_JSON_OBJECT(val, doc, distributions, distributions);
json::insert_into_json_object(val, doc, "status", status);
json::insert_into_json_object(val, doc, "distributions", distributions);
return val;
}
void GetOutputDistribution::Response::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, status, status);
GET_FROM_JSON_OBJECT(val, distributions, distributions);
json::load_from_json_object(val, "status", status);
json::load_from_json_object(val, "distributions", distributions);
}
} // namespace rpc

View File

@ -62,16 +62,16 @@ rapidjson::Value Message::toJson(rapidjson::Document& doc) const
val.AddMember("status", rapidjson::StringRef(status.c_str()), al);
val.AddMember("error_details", rapidjson::StringRef(error_details.c_str()), al);
INSERT_INTO_JSON_OBJECT(val, doc, rpc_version, DAEMON_RPC_VERSION_ZMQ);
json::insert_into_json_object(val, doc, "rpc_version", DAEMON_RPC_VERSION_ZMQ);
return val;
}
void Message::fromJson(rapidjson::Value& val)
{
GET_FROM_JSON_OBJECT(val, status, status);
GET_FROM_JSON_OBJECT(val, error_details, error_details);
GET_FROM_JSON_OBJECT(val, rpc_version, rpc_version);
json::load_from_json_object(val, "status", status);
json::load_from_json_object(val, "error_details", error_details);
json::load_from_json_object(val, "rpc_version", rpc_version);
}
@ -104,7 +104,7 @@ FullMessage::FullMessage(Message* message)
err.error_str = message->status;
err.message = message->error_details;
INSERT_INTO_JSON_OBJECT(doc, doc, error, err);
json::insert_into_json_object(doc, doc, "error", err);
}
}
@ -116,12 +116,12 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
throw cryptonote::json::PARSE_FAIL();
}
OBJECT_HAS_MEMBER_OR_THROW(doc, "jsonrpc")
json::require_member(doc, "jsonrpc");
if (request)
{
OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
json::require_member(doc, method_field);
json::require_member(doc, params_field);
}
else
{
@ -151,7 +151,7 @@ std::string FullMessage::getJson()
std::string FullMessage::getRequestType() const
{
OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
json::require_member(doc, method_field);
return doc[method_field].GetString();
}
@ -167,7 +167,7 @@ rapidjson::Value& FullMessage::getMessage()
}
//else
OBJECT_HAS_MEMBER_OR_THROW(doc, error_field)
json::require_member(doc, error_field);
return doc[error_field];
}
@ -181,7 +181,7 @@ rapidjson::Value FullMessage::getMessageCopy()
rapidjson::Value& FullMessage::getID()
{
OBJECT_HAS_MEMBER_OR_THROW(doc, id_field)
json::require_member(doc, id_field);
return doc[id_field];
}
@ -204,7 +204,7 @@ cryptonote::rpc::error FullMessage::getError()
err.use = false;
if (doc.HasMember(error_field))
{
GET_FROM_JSON_OBJECT(doc, err, error);
json::load_from_json_object(doc, "error", err);
err.use = true;
}
@ -250,7 +250,7 @@ FullMessage* FullMessage::timeoutMessage()
cryptonote::rpc::error err;
err.error_str = "RPC request timed out.";
INSERT_INTO_JSON_OBJECT(doc, doc, err, err);
json::insert_into_json_object(doc, doc, "err", err);
return full_message;
}

View File

@ -3894,8 +3894,11 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
std::string tmp_file_name = keys_file_name + ".new";
std::string buf;
bool r = ::serialization::dump_binary(keys_file_data.get(), buf);
r = r && save_to_file(tmp_file_name, buf);
bool r;
try {
buf = serialization::dump_binary(keys_file_data);
r = save_to_file(tmp_file_name, buf);
} catch (...) {}
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << tmp_file_name);
unlock_keys_file();
@ -3964,13 +3967,21 @@ boost::optional<wallet2::keys_file_data> wallet2::get_keys_file_data(const epee:
if (m_multisig)
{
bool r = ::serialization::dump_binary(m_multisig_signers, multisig_signers);
CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig signers");
try {
multisig_signers = serialization::dump_binary(m_multisig_signers);
} catch (const std::exception& e) {
LOG_ERROR("failed to serialize wallet multisig signers: " << e.what());
return boost::none;
}
value.SetString(multisig_signers.c_str(), multisig_signers.length());
json.AddMember("multisig_signers", value, json.GetAllocator());
r = ::serialization::dump_binary(m_multisig_derivations, multisig_derivations);
CHECK_AND_ASSERT_MES(r, boost::none, "failed to serialize wallet multisig derivations");
try {
multisig_derivations = serialization::dump_binary(m_multisig_derivations);
} catch (const std::exception& e) {
LOG_ERROR("failed to serialize wallet multisig derivations");
return boost::none;
}
value.SetString(multisig_derivations.c_str(), multisig_derivations.length());
json.AddMember("multisig_derivations", value, json.GetAllocator());
@ -4171,8 +4182,11 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
rapidjson::Document json;
wallet2::keys_file_data keys_file_data;
bool encrypted_secret_keys = false;
bool r = ::serialization::parse_binary(keys_buf, keys_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize keys buffer");
try {
serialization::parse_binary(keys_buf, keys_file_data);
} catch (const std::exception& e) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "internal error: failed to deserialize keys buffer: " + e.what());
}
crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds);
std::string account_data;
@ -4270,10 +4284,10 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
}
const char *field_multisig_signers = json["multisig_signers"].GetString();
std::string multisig_signers = std::string(field_multisig_signers, field_multisig_signers + json["multisig_signers"].GetStringLength());
r = ::serialization::parse_binary(multisig_signers, m_multisig_signers);
if (!r)
{
LOG_ERROR("Field multisig_signers found in JSON, but failed to parse");
try {
serialization::parse_binary(multisig_signers, m_multisig_signers);
} catch (const std::exception& e) {
LOG_ERROR("Field multisig_signers found in JSON, but failed to parse: " << e.what());
return false;
}
@ -4287,10 +4301,10 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
}
const char *field_multisig_derivations = json["multisig_derivations"].GetString();
std::string multisig_derivations = std::string(field_multisig_derivations, field_multisig_derivations + json["multisig_derivations"].GetStringLength());
r = ::serialization::parse_binary(multisig_derivations, m_multisig_derivations);
if (!r)
{
LOG_ERROR("Field multisig_derivations found in JSON, but failed to parse");
try {
serialization::parse_binary(multisig_derivations, m_multisig_derivations);
} catch (const std::exception& e) {
LOG_ERROR("Field multisig_derivations found in JSON, but failed to parse: " << e.what());
return false;
}
}
@ -4437,7 +4451,7 @@ bool wallet2::load_keys_buf(const std::string& keys_buf, const epee::wipeable_st
return false;
}
r = epee::serialization::load_t_from_binary(m_account, account_data);
bool r = epee::serialization::load_t_from_binary(m_account, account_data);
THROW_WALLET_EXCEPTION_IF(!r, error::invalid_password);
if (m_key_device_type == hw::device::device_type::LEDGER || m_key_device_type == hw::device::device_type::TREZOR) {
LOG_PRINT_L0("Account on device. Initing device...");
@ -4527,8 +4541,11 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
r = ::serialization::parse_binary(buf, keys_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
try {
serialization::parse_binary(buf, keys_file_data);
} catch (const std::exception& e) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + "\": " + e.what());
}
crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
std::string account_data;
@ -4640,8 +4657,11 @@ bool wallet2::query_device(hw::device::device_type& device_type, const std::stri
THROW_WALLET_EXCEPTION_IF(!r, error::file_read_error, keys_file_name);
// Decrypt the contents
r = ::serialization::parse_binary(buf, keys_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"');
try {
serialization::parse_binary(buf, keys_file_data);
} catch (const std::exception& e) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + "\": " + e.what());
}
crypto::chacha_key key;
crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds);
std::string account_data;
@ -5748,8 +5768,11 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass
{
LOG_PRINT_L1("Trying to decrypt cache data");
r = ::serialization::parse_binary(use_fs ? cache_file_buf : cache_buf, cache_file_data);
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + '\"');
try {
serialization::parse_binary(use_fs ? cache_file_buf : cache_buf, cache_file_data);
} catch (const std::exception& e) {
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "internal error: failed to deserialize \"" + m_wallet_file + "\": " + e.what());
}
std::string cache_data;
cache_data.resize(cache_file_data.cache_data.size());
crypto::chacha20(cache_file_data.cache_data.data(), cache_file_data.cache_data.size(), m_cache_key, cache_file_data.iv, &cache_data[0]);
@ -5998,20 +6021,21 @@ void wallet2::store_to(const std::string &path, const epee::wipeable_string &pas
#ifdef WIN32
// On Windows avoid using std::ofstream which does not work with UTF-8 filenames
// The price to pay is temporary higher memory consumption for string stream + binary archive
std::ostringstream oss;
binary_archive<true> oar(oss);
bool success = ::serialization::serialize(oar, cache_file_data.get());
if (success) {
success = save_to_file(new_file, oss.str());
}
bool success = false;
try {
serialization::binary_string_archiver oar;
serialization::serialize(oar, cache_file_data.get());
success = save_to_file(new_file, oss.str());
} catch (...) {}
THROW_WALLET_EXCEPTION_IF(!success, error::file_save_error, new_file);
#else
std::ofstream ostr;
ostr.open(new_file, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
binary_archive<true> oar(ostr);
bool success = ::serialization::serialize(oar, cache_file_data.get());
ostr.close();
THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file);
try {
std::ofstream ostr{new_file, std::ios_base::binary | std::ios_base::trunc};
serialization::binary_archiver oar{ostr};
serialization::serialize(oar, cache_file_data.get());
} catch (const std::exception& e) {
THROW_WALLET_EXCEPTION(error::file_save_error, new_file);
}
#endif
// here we have "*.new" file, we need to rename it to be without ".new"

View File

@ -30,6 +30,7 @@
#pragma once
#include "cryptonote_basic/cryptonote_basic.h"
#include "serialization/vector.h"
#include "crypto/hash.h"
namespace tools

View File

@ -220,12 +220,12 @@ private:
};
VARIANT_TAG(binary_archive, callback_entry, 0xcb);
VARIANT_TAG(binary_archive, cryptonote::account_base, 0xcc);
VARIANT_TAG(binary_archive, serialized_block, 0xcd);
VARIANT_TAG(binary_archive, serialized_transaction, 0xce);
VARIANT_TAG(binary_archive, event_visitor_settings, 0xcf);
VARIANT_TAG(binary_archive, event_replay_settings, 0xda);
BINARY_VARIANT_TAG(callback_entry, 0xcb);
BINARY_VARIANT_TAG(cryptonote::account_base, 0xcc);
BINARY_VARIANT_TAG(serialized_block, 0xcd);
BINARY_VARIANT_TAG(serialized_transaction, 0xce);
BINARY_VARIANT_TAG(event_visitor_settings, 0xcf);
BINARY_VARIANT_TAG(event_replay_settings, 0xda);
typedef boost::variant<cryptonote::block,
cryptonote::transaction,
@ -719,12 +719,10 @@ public:
bvc.m_verifivation_failed = true;
cryptonote::block blk;
std::stringstream ss;
ss << sr_block.data;
binary_archive<false> ba(ss);
::serialization::serialize(ba, blk);
if (!ss.good())
{
serialization::binary_string_unarchiver ba{sr_block.data};
try {
serialization::serialize(ba, blk);
} catch (...) {
blk = cryptonote::block();
}
bool r = m_validator.check_block_verification_context(bvc, m_ev_index, blk);
@ -744,12 +742,10 @@ public:
bool tx_added = pool_size + 1 == m_c.get_pool().get_transactions_count();
cryptonote::transaction tx;
std::stringstream ss;
ss << sr_tx.data;
binary_archive<false> ba(ss);
::serialization::serialize(ba, tx);
if (!ss.good())
{
serialization::binary_string_unarchiver ba{sr_tx.data};
try {
serialization::serialize(ba, tx);
} catch (...) {
tx = cryptonote::transaction();
}

View File

@ -50,14 +50,12 @@ int BulletproofFuzzer::run(const std::string &filename)
std::cout << "Error: failed to load file " << filename << std::endl;
return 1;
}
std::stringstream ss;
ss << s;
binary_archive<false> ba(ss);
serialization::binary_string_unarchiver ba{s};
rct::Bulletproof proof{};
bool r = ::serialization::serialize(ba, proof);
if(!r)
{
std::cout << "Error: failed to parse bulletproof from file " << filename << std::endl;
try {
serialization::serialize(ba, proof);
} catch (const std::exception& e) {
std::cout << "Error: failed to parse bulletproof from file " << filename << ": " << e.what() << "\n";
return 1;
}
return 0;

View File

@ -473,7 +473,7 @@ namespace
TEST(get_account_address_as_str, works_correctly)
{
cryptonote::account_public_address addr;
ASSERT_TRUE(serialization::parse_binary(test_serialized_keys, addr));
ASSERT_NO_THROW(serialization::parse_binary(test_serialized_keys, addr));
std::string addr_str = cryptonote::get_account_address_as_str(cryptonote::MAINNET, false, addr);
ASSERT_EQ(addr_str, test_keys_addr_str);
}
@ -484,7 +484,7 @@ TEST(get_account_address_from_str, handles_valid_address)
ASSERT_TRUE(cryptonote::get_account_address_from_str(info, cryptonote::MAINNET, test_keys_addr_str));
std::string blob;
ASSERT_TRUE(serialization::dump_binary(info.address, blob));
ASSERT_NO_THROW(blob = serialization::dump_binary(info.address));
ASSERT_EQ(blob, test_serialized_keys);
}

View File

@ -269,21 +269,10 @@ TEST(sort_tx_extra, invalid)
ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
}
TEST(sort_tx_extra, invalid_suffix_strict)
TEST(sort_tx_extra, invalid_suffix)
{
std::vector<uint8_t> sorted;
const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
ASSERT_FALSE(cryptonote::sort_tx_extra(extra, sorted));
}
TEST(sort_tx_extra, invalid_suffix_partial)
{
std::vector<uint8_t> sorted;
const uint8_t extra_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
const uint8_t expected_arr[] = {2, 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1};
std::vector<uint8_t> extra(&extra_arr[0], &extra_arr[0] + sizeof(extra_arr));
ASSERT_TRUE(cryptonote::sort_tx_extra(extra, sorted, true));
std::vector<uint8_t> expected(&expected_arr[0], &expected_arr[0] + sizeof(expected_arr));
ASSERT_EQ(sorted, expected);
}