diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index f516b24..3376a17 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -1,7 +1,7 @@ #pragma once #define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0 -#define CURRENT_TRANSACTION_VERSION 1 +#define CURRENT_TRANSACTION_VERSION 2 #define CURRENT_BLOCK_MAJOR_VERSION 1 #define CURRENT_BLOCK_MINOR_VERSION 0 diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index f9e6727..a4c2b3d 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -24,6 +24,7 @@ #include "crypto/hash.h" #include "misc_language.h" #include "tx_extra.h" +#include "ringct/rctTypes.h" namespace cryptonote @@ -189,6 +190,7 @@ namespace cryptonote { public: std::vector > signatures; //count signatures always the same as inputs count + rct::rctSig rct_signatures; transaction(); virtual ~transaction(); @@ -197,34 +199,57 @@ namespace cryptonote BEGIN_SERIALIZE_OBJECT() FIELDS(*static_cast(this)) - 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; - - for (size_t i = 0; i < vin.size(); ++i) + if (version == 1) { - size_t signature_size = get_signature_size(vin[i]); - if (signatures_not_expected) - { - if (0 == signature_size) - continue; - else - return false; - } - - PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); - if (signature_size != signatures[i].size()) + 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; - FIELDS(signatures[i]); + for (size_t i = 0; i < vin.size(); ++i) + { + size_t signature_size = get_signature_size(vin[i]); + if (signatures_not_expected) + { + if (0 == signature_size) + continue; + else + return false; + } - if (vin.size() - i > 1) - ar.delimit_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); + if (signature_size != signatures[i].size()) + return false; + + FIELDS(signatures[i]); + + if (vin.size() - i > 1) + ar.delimit_array(); + } + 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(); + if (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[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); + if (!r || !ar.stream().good()) return false; + ar.end_object(); + } + } } - ar.end_array(); END_SERIALIZE() private: diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 739b3b6..caa9bc3 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -613,10 +613,65 @@ namespace cryptonote return get_object_hash(static_cast(t), res, blob_size); } + //--------------------------------------------------------------- + bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size) + { + // v1 transactions hash the entire blob + if (t.version == 1) + { + size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size; + return get_object_hash(t, res, blob_size_ref); + } + + // v2 transactions hash different parts together, than hash the set of those hashes + crypto::hash hashes[3]; + + // prefix + get_transaction_prefix_hash(t, hashes[0]); + + transaction &tt = const_cast(t); + + // base rct + { + std::stringstream ss; + binary_archive ba(ss); + 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_MES(r, false, "Failed to serialize rct signatures base"); + cryptonote::get_blob_hash(ss.str(), hashes[1]); + } + + // prunable rct + if (t.rct_signatures.type == rct::RCTTypeNull) + { + hashes[2] = cryptonote::null_hash; + } + else + { + std::stringstream ss; + binary_archive ba(ss); + 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(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(), hashes[2]); + } + + // the tx hash is the hash of the 3 hashes + res = cn_fast_hash(hashes, sizeof(hashes)); + + // we still need the size + if (blob_size) + *blob_size = get_object_blobsize(t); + + return true; + } //--------------------------------------------------------------- bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size) { - return get_object_hash(t, res, blob_size); + return get_transaction_hash(t, res, &blob_size); } //--------------------------------------------------------------- bool get_block_hashing_blob(const block& b, blobdata& blob) diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index a91349c..09dfd1a 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -79,6 +79,7 @@ namespace cryptonote bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size); bool get_block_hashing_blob(const block& b, blobdata& blob); bool get_bytecoin_block_hashing_blob(const block& b, blobdata& blob); + blobdata get_block_hashing_blob(const block& b); blobdata get_block_hashing_blob(const bb_block& b); bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b);