aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-03-22 18:01:09 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2017-03-23 09:25:17 +0000
commitf065234b71f2e3d374d44435d47db4cd75ab1294 (patch)
tree9cd0f1fae6e0eaef9cfd677f085df88a9aa5250b /src/cryptonote_basic
parentMerge pull request #1901 (diff)
downloadmonero-f065234b71f2e3d374d44435d47db4cd75ab1294.tar.xz
core: cache tx and block hashes in the respective classes
An idea from smooth
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h32
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp79
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h3
-rw-r--r--src/cryptonote_basic/miner.cpp2
4 files changed, 114 insertions, 2 deletions
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index ed2787cf7..3492ace2b 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -190,11 +190,24 @@ namespace cryptonote
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
rct::rctSig rct_signatures;
+ // hash cash
+ mutable crypto::hash hash;
+ mutable size_t blob_size;
+ mutable bool hash_valid;
+ mutable bool blob_size_valid;
+
transaction();
virtual ~transaction();
void set_null();
+ void invalidate_hashes();
BEGIN_SERIALIZE_OBJECT()
+ if (!typename Archive<W>::is_saving())
+ {
+ hash_valid = false;
+ blob_size_valid = false;
+ }
+
FIELDS(*static_cast<transaction_prefix *>(this))
if (version == 1)
@@ -299,6 +312,15 @@ namespace cryptonote
extra.clear();
signatures.clear();
rct_signatures.type = rct::RCTTypeNull;
+ hash_valid = false;
+ blob_size_valid = false;
+ }
+
+ inline
+ void transaction::invalidate_hashes()
+ {
+ hash_valid = false;
+ blob_size_valid = false;
}
inline
@@ -339,10 +361,20 @@ namespace cryptonote
struct block: public block_header
{
+ block(): block_header(), hash_valid(false) {}
+ void invalidate_hashes() { hash_valid = false; }
+
transaction miner_tx;
std::vector<crypto::hash> tx_hashes;
+ // hash cash
+ mutable crypto::hash hash;
+ mutable bool hash_valid;
+
BEGIN_SERIALIZE_OBJECT()
+ if (!typename Archive<W>::is_saving())
+ hash_valid = false;
+
FIELDS(*static_cast<block_header *>(this))
FIELD(miner_tx)
FIELD(tx_hashes)
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 00e7b9d80..2f23194c8 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -43,6 +43,8 @@ using namespace epee;
#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d
+// #define ENABLE_HASH_CASH_INTEGRITY_CHECK
+
static const uint64_t valid_decomposed_outputs[] = {
(uint64_t)1, (uint64_t)2, (uint64_t)3, (uint64_t)4, (uint64_t)5, (uint64_t)6, (uint64_t)7, (uint64_t)8, (uint64_t)9, // 1 piconero
(uint64_t)10, (uint64_t)20, (uint64_t)30, (uint64_t)40, (uint64_t)50, (uint64_t)60, (uint64_t)70, (uint64_t)80, (uint64_t)90,
@@ -68,6 +70,11 @@ static const uint64_t valid_decomposed_outputs[] = {
static std::atomic<unsigned int> default_decimal_point(CRYPTONOTE_DISPLAY_DECIMAL_POINT);
+static std::atomic<uint64_t> tx_hashes_calculated_count(0);
+static std::atomic<uint64_t> tx_hashes_cached_count(0);
+static std::atomic<uint64_t> block_hashes_calculated_count(0);
+static std::atomic<uint64_t> block_hashes_cached_count(0);
+
namespace cryptonote
{
//---------------------------------------------------------------
@@ -93,6 +100,8 @@ 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");
+ tx.hash_valid = false;
+ tx.blob_size_valid = false;
return true;
}
//---------------------------------------------------------------
@@ -113,6 +122,8 @@ 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");
+ tx.hash_valid = false;
+ tx.blob_size_valid = false;
//TODO: validate tx
get_transaction_hash(tx, tx_hash);
@@ -592,7 +603,7 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL);
}
//---------------------------------------------------------------
- bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
+ bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
{
// v1 transactions hash the entire blob
if (t.version == 1)
@@ -647,6 +658,40 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
+ bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size)
+ {
+ if (t.hash_valid)
+ {
+#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
+ CHECK_AND_ASSERT_THROW_MES(!calculate_transaction_hash(t, res, blob_size) || t.hash == res, "tx hash cash integrity failure");
+#endif
+ res = t.hash;
+ if (blob_size)
+ {
+ if (!t.blob_size_valid)
+ {
+ t.blob_size = get_object_blobsize(t);
+ t.blob_size_valid = true;
+ }
+ *blob_size = t.blob_size;
+ }
+ ++tx_hashes_cached_count;
+ return true;
+ }
+ ++tx_hashes_calculated_count;
+ bool ret = calculate_transaction_hash(t, res, blob_size);
+ if (!ret)
+ return false;
+ t.hash = res;
+ t.hash_valid = true;
+ if (blob_size)
+ {
+ t.blob_size = *blob_size;
+ t.blob_size_valid = true;
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t& blob_size)
{
return get_transaction_hash(t, res, &blob_size);
@@ -661,7 +706,7 @@ namespace cryptonote
return blob;
}
//---------------------------------------------------------------
- bool get_block_hash(const block& b, crypto::hash& res)
+ bool calculate_block_hash(const block& b, crypto::hash& res)
{
// EXCEPTION FOR BLOCK 202612
const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966";
@@ -688,6 +733,26 @@ namespace cryptonote
return hash_result;
}
//---------------------------------------------------------------
+ bool get_block_hash(const block& b, crypto::hash& res)
+ {
+ if (b.hash_valid)
+ {
+#ifdef ENABLE_HASH_CASH_INTEGRITY_CHECK
+ CHECK_AND_ASSERT_THROW_MES(!calculate_block_hash(b, res) || b.hash == res, "block hash cash integrity failure");
+#endif
+ res = b.hash;
+ ++block_hashes_cached_count;
+ return true;
+ }
+ ++block_hashes_calculated_count;
+ bool ret = calculate_block_hash(b, res);
+ if (!ret)
+ return false;
+ b.hash = res;
+ b.hash_valid = true;
+ return true;
+ }
+ //---------------------------------------------------------------
crypto::hash get_block_hash(const block& b)
{
crypto::hash p = null_hash;
@@ -744,6 +809,9 @@ namespace cryptonote
binary_archive<false> ba(ss);
bool r = ::serialization::serialize(ba, b);
CHECK_AND_ASSERT_MES(r, false, "Failed to parse block from blob");
+ b.hash_valid = false;
+ b.miner_tx.hash_valid = false;
+ b.miner_tx.blob_size_valid = false;
return true;
}
//---------------------------------------------------------------
@@ -798,4 +866,11 @@ namespace cryptonote
return std::binary_search(begin, end, amount);
}
//---------------------------------------------------------------
+ void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached)
+ {
+ tx_hashes_calculated = tx_hashes_calculated_count;
+ tx_hashes_cached = tx_hashes_cached_count;
+ block_hashes_calculated = block_hashes_calculated_count;
+ block_hashes_cached = block_hashes_cached_count;
+ }
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 7b09235b8..5c10907fd 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -85,7 +85,9 @@ 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_hash(const transaction& t, crypto::hash& res, size_t* blob_size);
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);
crypto::hash get_block_hash(const block& b);
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height);
@@ -209,6 +211,7 @@ namespace cryptonote
crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes);
crypto::hash get_tx_tree_hash(const block& b);
bool is_valid_decomposed_amount(uint64_t amount);
+ void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached);
#define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \
CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index 1725b7541..5a2a0d009 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -355,9 +355,11 @@ namespace cryptonote
if(check_hash(h, diffic))
{
+ bl.hash_valid = false;
return true;
}
}
+ bl.hash_valid = false;
return false;
}
//-----------------------------------------------------------------------------------------------------