diff options
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r-- | src/cryptonote_basic/cryptonote_format_utils.cpp | 101 | ||||
-rw-r--r-- | src/cryptonote_basic/cryptonote_format_utils.h | 4 | ||||
-rw-r--r-- | src/cryptonote_basic/hardfork.cpp | 18 |
3 files changed, 108 insertions, 15 deletions
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index ae7c1c0ae..428be1c9c 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -124,6 +124,40 @@ namespace cryptonote return h; } //--------------------------------------------------------------- + bool expand_transaction_1(transaction &tx, bool base_only) + { + if (tx.version >= 2 && !is_coinbase(tx)) + { + rct::rctSig &rv = tx.rct_signatures; + if (rv.outPk.size() != tx.vout.size()) + { + LOG_PRINT_L1("Failed to parse transaction from blob, bad outPk size in tx " << get_transaction_hash(tx)); + return false; + } + for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n) + rv.outPk[n].dest = rct::pk2rct(boost::get<txout_to_key>(tx.vout[n].target).key); + + if (!base_only) + { + const bool bulletproof = rv.type == rct::RCTTypeFullBulletproof || rv.type == rct::RCTTypeSimpleBulletproof; + if (bulletproof) + { + if (rv.p.bulletproofs.size() != tx.vout.size()) + { + LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs size in tx " << get_transaction_hash(tx)); + return false; + } + for (size_t n = 0; n < rv.outPk.size(); ++n) + { + rv.p.bulletproofs[n].V.resize(1); + rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask; + } + } + } + } + return true; + } + //--------------------------------------------------------------- bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx) { std::stringstream ss; @@ -131,6 +165,7 @@ namespace cryptonote binary_archive<false> ba(ss); bool r = ::serialization::serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); + CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data"); tx.invalidate_hashes(); return true; } @@ -142,6 +177,7 @@ namespace cryptonote binary_archive<false> ba(ss); bool r = tx.serialize_base(ba); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); + CHECK_AND_ASSERT_MES(expand_transaction_1(tx, true), false, "Failed to expand transaction data"); return true; } //--------------------------------------------------------------- @@ -152,6 +188,7 @@ namespace cryptonote binary_archive<false> ba(ss); bool r = ::serialization::serialize(ba, tx); CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob"); + CHECK_AND_ASSERT_MES(expand_transaction_1(tx, false), false, "Failed to expand transaction data"); tx.invalidate_hashes(); //TODO: validate tx @@ -742,6 +779,61 @@ namespace cryptonote return get_transaction_hash(t, res, NULL); } //--------------------------------------------------------------- + bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res) + { + if (t.version == 1) + return false; + transaction &tt = const_cast<transaction&>(t); + std::stringstream ss; + binary_archive<true> 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<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); + return true; + } + //--------------------------------------------------------------- + crypto::hash get_transaction_prunable_hash(const transaction& t) + { + crypto::hash res; + CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, res), "Failed to calculate tx prunable hash"); + return res; + } + //--------------------------------------------------------------- + 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 > 1, "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]; + + // prefix + get_transaction_prefix_hash(t, hashes[0]); + + transaction &tt = const_cast<transaction&>(t); + + // base rct + { + std::stringstream ss; + binary_archive<true> 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_THROW_MES(r, "Failed to serialize rct signatures base"); + cryptonote::get_blob_hash(ss.str(), hashes[1]); + } + + // prunable rct + hashes[2] = pruned_data_hash; + + // the tx hash is the hash of the 3 hashes + crypto::hash res = cn_fast_hash(hashes, sizeof(hashes)); + return res; + } + //--------------------------------------------------------------- bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size) { // v1 transactions hash the entire blob @@ -777,14 +869,7 @@ namespace cryptonote } else { - std::stringstream ss; - binary_archive<true> 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<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(), hashes[2]); + CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, hashes[2]), false, "Failed to get tx prunable hash"); } // the tx hash is the hash of the 3 hashes diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 79466e9c4..8a5296d5b 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -100,7 +100,11 @@ namespace cryptonote bool get_transaction_hash(const transaction& t, crypto::hash& res); bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size); bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size); + bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res); + crypto::hash get_transaction_prunable_hash(const transaction& t); bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size); + crypto::hash get_pruned_transaction_hash(const transaction& t, const crypto::hash &pruned_data_hash); + blobdata get_block_hashing_blob(const block& b); bool calculate_block_hash(const block& b, crypto::hash& res); bool get_block_hash(const block& b, crypto::hash& res); diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp index 95f1ecab9..f05b25901 100644 --- a/src/cryptonote_basic/hardfork.cpp +++ b/src/cryptonote_basic/hardfork.cpp @@ -379,20 +379,24 @@ uint8_t HardFork::get_ideal_version(uint64_t height) const uint64_t HardFork::get_earliest_ideal_height_for_version(uint8_t version) const { - for (unsigned int n = heights.size() - 1; n > 0; --n) { - if (heights[n].version <= version) - return heights[n].height; + uint64_t height = std::numeric_limits<uint64_t>::max(); + for (auto i = heights.rbegin(); i != heights.rend(); ++i) { + if (i->version >= version) { + height = i->height; + } else { + break; + } } - return 0; + return height; } uint8_t HardFork::get_next_version() const { CRITICAL_REGION_LOCAL(lock); uint64_t height = db.height(); - for (unsigned int n = heights.size() - 1; n > 0; --n) { - if (height >= heights[n].height) { - return heights[n < heights.size() - 1 ? n + 1 : n].version; + for (auto i = heights.rbegin(); i != heights.rend(); ++i) { + if (height >= i->height) { + return (i == heights.rbegin() ? i : (i - 1))->version; } } return original_version; |