mirror of https://github.com/oxen-io/oxen-core.git
Serialization (part2): application
This commit is contained in:
parent
799aa6aed5
commit
a506790f1c
|
@ -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"));
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "serialization/vector.h"
|
||||
#include "crypto/hash.h"
|
||||
|
||||
namespace tools
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue