aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/CMakeLists.txt2
-rw-r--r--src/cryptonote_basic/account.cpp2
-rw-r--r--src/cryptonote_basic/account.h2
-rw-r--r--src/cryptonote_basic/account_boost_serialization.h2
-rw-r--r--src/cryptonote_basic/blobdatatype.h6
-rw-r--r--src/cryptonote_basic/connection_context.h27
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h38
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp2
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h2
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h9
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp100
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h11
-rw-r--r--src/cryptonote_basic/cryptonote_stat_info.h5
-rw-r--r--src/cryptonote_basic/difficulty.cpp2
-rw-r--r--src/cryptonote_basic/difficulty.h2
-rw-r--r--src/cryptonote_basic/hardfork.cpp28
-rw-r--r--src/cryptonote_basic/hardfork.h12
-rw-r--r--src/cryptonote_basic/miner.cpp97
-rw-r--r--src/cryptonote_basic/miner.h11
-rw-r--r--src/cryptonote_basic/subaddress_index.h2
-rw-r--r--src/cryptonote_basic/tx_extra.h2
-rw-r--r--src/cryptonote_basic/verification_context.h2
22 files changed, 297 insertions, 69 deletions
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
index 21445959d..5bb56e083 100644
--- a/src/cryptonote_basic/CMakeLists.txt
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -1,4 +1,4 @@
-# Copyright (c) 2014-2018, The Monero Project
+# Copyright (c) 2014-2019, The Monero Project
#
# All rights reserved.
#
diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp
index edbc2c561..a9aec163b 100644
--- a/src/cryptonote_basic/account.cpp
+++ b/src/cryptonote_basic/account.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
index 021f84029..abf751b6e 100644
--- a/src/cryptonote_basic/account.h
+++ b/src/cryptonote_basic/account.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/account_boost_serialization.h b/src/cryptonote_basic/account_boost_serialization.h
index 7379d787f..320a960dc 100644
--- a/src/cryptonote_basic/account_boost_serialization.h
+++ b/src/cryptonote_basic/account_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/blobdatatype.h b/src/cryptonote_basic/blobdatatype.h
index 7d6ff0187..20f6b2421 100644
--- a/src/cryptonote_basic/blobdatatype.h
+++ b/src/cryptonote_basic/blobdatatype.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -30,7 +30,11 @@
#pragma once
+#include <string>
+#include "span.h"
+
namespace cryptonote
{
typedef std::string blobdata;
+ typedef epee::span<const char> blobdata_ref;
}
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
index eb73ab0ea..96398a90b 100644
--- a/src/cryptonote_basic/connection_context.h
+++ b/src/cryptonote_basic/connection_context.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -40,7 +40,8 @@ namespace cryptonote
struct cryptonote_connection_context: public epee::net_utils::connection_context_base
{
cryptonote_connection_context(): m_state(state_before_handshake), m_remote_blockchain_height(0), m_last_response_height(0),
- m_last_request_time(boost::posix_time::microsec_clock::universal_time()), m_callback_request_count(0), m_last_known_hash(crypto::null_hash) {}
+ m_last_request_time(boost::date_time::not_a_date_time), m_callback_request_count(0),
+ m_last_known_hash(crypto::null_hash), m_pruning_seed(0), m_rpc_port(0), m_anchor(false) {}
enum state
{
@@ -59,6 +60,9 @@ namespace cryptonote
boost::posix_time::ptime m_last_request_time;
epee::copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
crypto::hash m_last_known_hash;
+ uint32_t m_pruning_seed;
+ uint16_t m_rpc_port;
+ bool m_anchor;
//size_t m_score; TODO: add score calculations
};
@@ -81,4 +85,23 @@ namespace cryptonote
}
}
+ inline char get_protocol_state_char(cryptonote_connection_context::state s)
+ {
+ switch (s)
+ {
+ case cryptonote_connection_context::state_before_handshake:
+ return 'h';
+ case cryptonote_connection_context::state_synchronizing:
+ return 's';
+ case cryptonote_connection_context::state_standby:
+ return 'w';
+ case cryptonote_connection_context::state_idle:
+ return 'i';
+ case cryptonote_connection_context::state_normal:
+ return 'n';
+ default:
+ return 'u';
+ }
+ }
+
}
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
index 196b20e2a..03caafbb0 100644
--- a/src/cryptonote_basic/cryptonote_basic.h
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -152,6 +152,10 @@ 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(); }
+
class transaction_prefix
{
@@ -201,9 +205,14 @@ namespace cryptonote
mutable crypto::hash hash;
mutable size_t blob_size;
+ bool pruned;
+
+ std::atomic<unsigned int> unprunable_size;
+ std::atomic<unsigned int> prefix_size;
+
transaction();
- transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } }
- transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } return *this; }
+ transaction(const transaction &t): transaction_prefix(t), hash_valid(false), blob_size_valid(false), signatures(t.signatures), rct_signatures(t.rct_signatures), pruned(t.pruned), unprunable_size(t.unprunable_size.load()), prefix_size(t.prefix_size.load()) { if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } }
+ transaction &operator=(const transaction &t) { transaction_prefix::operator=(t); set_hash_valid(false); set_blob_size_valid(false); signatures = t.signatures; rct_signatures = t.rct_signatures; if (t.is_hash_valid()) { hash = t.hash; set_hash_valid(true); } if (t.is_blob_size_valid()) { blob_size = t.blob_size; set_blob_size_valid(true); } pruned = t.pruned; unprunable_size = t.unprunable_size.load(); prefix_size = t.prefix_size.load(); return *this; }
virtual ~transaction();
void set_null();
void invalidate_hashes();
@@ -221,10 +230,18 @@ namespace cryptonote
set_blob_size_valid(false);
}
+ const unsigned int start_pos = getpos(ar);
+
FIELDS(*static_cast<transaction_prefix *>(this))
+ if (std::is_same<Archive<W>, binary_archive<W>>())
+ prefix_size = getpos(ar) - start_pos;
+
if (version == 1)
{
+ if (std::is_same<Archive<W>, binary_archive<W>>())
+ unprunable_size = getpos(ar) - start_pos;
+
ar.tag("signatures");
ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures);
@@ -232,7 +249,7 @@ namespace cryptonote
if (!signatures_not_expected && vin.size() != signatures.size())
return false;
- for (size_t i = 0; i < vin.size(); ++i)
+ if (!pruned) for (size_t i = 0; i < vin.size(); ++i)
{
size_t signature_size = get_signature_size(vin[i]);
if (signatures_not_expected)
@@ -263,7 +280,11 @@ namespace cryptonote
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)
+
+ if (std::is_same<Archive<W>, binary_archive<W>>())
+ unprunable_size = getpos(ar) - start_pos;
+
+ if (!pruned && rct_signatures.type != rct::RCTTypeNull)
{
ar.tag("rctsig_prunable");
ar.begin_object();
@@ -274,6 +295,8 @@ namespace cryptonote
}
}
}
+ if (!typename Archive<W>::is_saving())
+ pruned = false;
END_SERIALIZE()
template<bool W, template <bool> class Archive>
@@ -295,6 +318,8 @@ namespace cryptonote
ar.end_object();
}
}
+ if (!typename Archive<W>::is_saving())
+ pruned = true;
return true;
}
@@ -322,6 +347,9 @@ namespace cryptonote
rct_signatures.type = rct::RCTTypeNull;
set_hash_valid(false);
set_blob_size_valid(false);
+ pruned = false;
+ unprunable_size = 0;
+ prefix_size = 0;
}
inline
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
index 23a5bd5bd..e336cc1d1 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.cpp
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
index 0b8131a7a..036273f0e 100644
--- a/src/cryptonote_basic/cryptonote_basic_impl.h
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
index 0725a2bb8..4ce9f3eeb 100644
--- a/src/cryptonote_basic/cryptonote_boost_serialization.h
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -249,7 +249,6 @@ namespace boost
{
a & x.mask;
a & x.amount;
- // a & x.senderPk; // not serialized, as we do not use it in monero currently
}
template <class Archive>
@@ -295,7 +294,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
- if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof)
+ if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -323,7 +322,7 @@ namespace boost
a & x.type;
if (x.type == rct::RCTTypeNull)
return;
- if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof)
+ if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple && x.type != rct::RCTTypeBulletproof && x.type != rct::RCTTypeBulletproof2)
throw boost::archive::archive_exception(boost::archive::archive_exception::other_exception, "Unsupported rct type");
// a & x.message; message is not serialized, as it can be reconstructed from the tx data
// a & x.mixRing; mixRing is not serialized, as it can be reconstructed from the offsets
@@ -337,7 +336,7 @@ namespace boost
if (x.p.rangeSigs.empty())
a & x.p.bulletproofs;
a & x.p.MGs;
- if (x.type == rct::RCTTypeBulletproof)
+ if (x.type == rct::RCTTypeBulletproof || x.type == rct::RCTTypeBulletproof2)
a & x.p.pseudoOuts;
}
}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
index 82428f196..f40464bd1 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.cpp
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -196,6 +196,7 @@ namespace cryptonote
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");
+ tx.invalidate_hashes();
return true;
}
//---------------------------------------------------------------
@@ -209,7 +210,7 @@ namespace cryptonote
return true;
}
//---------------------------------------------------------------
- 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)
{
std::stringstream ss;
ss << tx_blob;
@@ -221,10 +222,33 @@ namespace cryptonote
//TODO: validate tx
get_transaction_hash(tx, tx_hash);
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool parse_and_validate_tx_from_blob(const blobdata& 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;
get_transaction_prefix_hash(tx, tx_prefix_hash);
return true;
}
//---------------------------------------------------------------
+ bool is_v1_tx(const blobdata_ref& 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)
+ 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 = AUTO_VAL_INIT(recv_derivation);
@@ -372,6 +396,7 @@ namespace cryptonote
for (const auto &bp: rv.p.bulletproofs)
nlr += bp.L.size() * 2;
const size_t bp_size = 32 * (9 + nlr);
+ CHECK_AND_ASSERT_THROW_MES_L1(n_outputs <= BULLETPROOF_MAX_OUTPUTS, "maximum number of outputs is " + std::to_string(BULLETPROOF_MAX_OUTPUTS) + " per transaction");
CHECK_AND_ASSERT_THROW_MES_L1(bp_base * n_padded_outputs >= bp_size, "Invalid bulletproof clawback");
const uint64_t bp_clawback = (bp_base * n_padded_outputs - bp_size) * 4 / 5;
CHECK_AND_ASSERT_THROW_MES_L1(bp_clawback <= std::numeric_limits<uint64_t>::max() - blob_size, "Weight overflow");
@@ -861,6 +886,11 @@ 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)
{
cn_fast_hash(blob.data(), blob.size(), res);
@@ -929,6 +959,13 @@ namespace cryptonote
return h;
}
//---------------------------------------------------------------
+ crypto::hash get_blob_hash(const epee::span<const char>& blob)
+ {
+ crypto::hash h = null_hash;
+ get_blob_hash(blob, h);
+ return h;
+ }
+ //---------------------------------------------------------------
crypto::hash get_transaction_hash(const transaction& t)
{
crypto::hash h = null_hash;
@@ -941,26 +978,42 @@ namespace cryptonote
return get_transaction_hash(t, res, NULL);
}
//---------------------------------------------------------------
- bool calculate_transaction_prunable_hash(const transaction& t, crypto::hash& res)
+ bool calculate_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, 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);
+ static const crypto::hash empty_hash = { (char)0x70, (char)0xa4, (char)0x85, (char)0x5d, (char)0x04, (char)0xd8, (char)0xfa, (char)0x7b, (char)0x3b, (char)0x27, (char)0x82, (char)0xca, (char)0x53, (char)0xb6, (char)0x00, (char)0xe5, (char)0xc0, (char)0x03, (char)0xc7, (char)0xdc, (char)0xb2, (char)0x7d, (char)0x7e, (char)0x92, (char)0x3c, (char)0x23, (char)0xf7, (char)0x86, (char)0x01, (char)0x46, (char)0xd2, (char)0xc5 };
+ const unsigned int unprunable_size = t.unprunable_size;
+ if (blob && unprunable_size)
+ {
+ CHECK_AND_ASSERT_MES(unprunable_size <= blob->size(), false, "Inconsistent transaction unprunable and blob sizes");
+ if (blob->size() - unprunable_size == 0)
+ res = empty_hash;
+ else
+ cryptonote::get_blob_hash(epee::span<const char>(blob->data() + unprunable_size, blob->size() - unprunable_size), res);
+ }
+ else
+ {
+ 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");
+ if (ss.str().empty())
+ res = empty_hash;
+ else
+ cryptonote::get_blob_hash(ss.str(), res);
+ }
return true;
}
//---------------------------------------------------------------
- crypto::hash get_transaction_prunable_hash(const transaction& t)
+ crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blobdata)
{
crypto::hash res;
- CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, res), "Failed to calculate tx prunable hash");
+ CHECK_AND_ASSERT_THROW_MES(calculate_transaction_prunable_hash(t, blobdata, res), "Failed to calculate tx prunable hash");
return res;
}
//---------------------------------------------------------------
@@ -1013,16 +1066,13 @@ namespace cryptonote
transaction &tt = const_cast<transaction&>(t);
+ const blobdata blob = tx_to_blob(t);
+ const unsigned int unprunable_size = t.unprunable_size;
+ const unsigned int prefix_size = t.prefix_size;
+
// 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_MES(r, false, "Failed to serialize rct signatures base");
- cryptonote::get_blob_hash(ss.str(), hashes[1]);
- }
+ CHECK_AND_ASSERT_MES(prefix_size <= unprunable_size && unprunable_size <= blob.size(), false, "Inconsistent transaction prefix, unprunable and blob sizes");
+ cryptonote::get_blob_hash(epee::span<const char>(blob.data() + prefix_size, unprunable_size - prefix_size), hashes[1]);
// prunable rct
if (t.rct_signatures.type == rct::RCTTypeNull)
@@ -1031,7 +1081,7 @@ namespace cryptonote
}
else
{
- CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, hashes[2]), false, "Failed to get tx prunable hash");
+ CHECK_AND_ASSERT_MES(calculate_transaction_prunable_hash(t, &blob, hashes[2]), false, "Failed to get tx prunable hash");
}
// the tx hash is the hash of the 3 hashes
@@ -1157,7 +1207,7 @@ namespace cryptonote
}
blobdata bd = get_block_hashing_blob(b);
const int cn_variant = b.major_version >= 7 ? b.major_version - 6 : 0;
- crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant);
+ crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant, height);
return true;
}
//---------------------------------------------------------------
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
index 8d33b1ca4..40a9907be 100644
--- a/src/cryptonote_basic/cryptonote_format_utils.h
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -51,8 +51,11 @@ namespace cryptonote
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);
template<typename T>
bool find_tx_extra_field_by_type(const std::vector<tx_extra_field>& tx_extra_fields, T& field, size_t index = 0)
@@ -96,15 +99,17 @@ namespace cryptonote
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);
std::string short_hash_str(const crypto::hash& h);
crypto::hash get_transaction_hash(const transaction& t);
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_prunable_hash(const transaction& t, const cryptonote::blobdata *blob, crypto::hash& res);
+ crypto::hash get_transaction_prunable_hash(const transaction& t, const cryptonote::blobdata *blob = NULL);
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);
diff --git a/src/cryptonote_basic/cryptonote_stat_info.h b/src/cryptonote_basic/cryptonote_stat_info.h
index c0be2144e..4cc1bc764 100644
--- a/src/cryptonote_basic/cryptonote_stat_info.h
+++ b/src/cryptonote_basic/cryptonote_stat_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -34,7 +34,7 @@
namespace cryptonote
{
- struct core_stat_info
+ struct core_stat_info_t
{
uint64_t tx_pool_size;
uint64_t blockchain_height;
@@ -50,4 +50,5 @@ namespace cryptonote
KV_SERIALIZE(top_block_id_str)
END_KV_SERIALIZE_MAP()
};
+ typedef epee::misc_utils::struct_init<core_stat_info_t> core_stat_info;
}
diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp
index 55e3e93b3..89b748a83 100644
--- a/src/cryptonote_basic/difficulty.cpp
+++ b/src/cryptonote_basic/difficulty.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
index b06538467..8da355b22 100644
--- a/src/cryptonote_basic/difficulty.h
+++ b/src/cryptonote_basic/difficulty.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
index 87a394918..ebfe45f37 100644
--- a/src/cryptonote_basic/hardfork.cpp
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -222,7 +222,6 @@ bool HardFork::reorganize_from_block_height(uint64_t height)
if (height >= db.height())
return false;
- db.set_batch_transactions(true);
bool stop_batch = db.batch_start();
versions.clear();
@@ -306,11 +305,34 @@ bool HardFork::rescan_from_chain_height(uint64_t height)
return rescan_from_block_height(height - 1);
}
+void HardFork::on_block_popped(uint64_t nblocks)
+{
+ CHECK_AND_ASSERT_THROW_MES(nblocks > 0, "nblocks must be greater than 0");
+
+ CRITICAL_REGION_LOCAL(lock);
+
+ const uint64_t new_chain_height = db.height();
+ const uint64_t old_chain_height = new_chain_height + nblocks;
+ uint8_t version;
+ uint64_t height;
+ for (height = old_chain_height - 1; height >= new_chain_height; --height)
+ {
+ versions.pop_back();
+ version = db.get_hard_fork_version(height);
+ versions.push_front(version);
+ }
+
+ // does not take voting into account
+ for (current_fork_index = heights.size() - 1; current_fork_index > 0; --current_fork_index)
+ if (height >= heights[current_fork_index].height)
+ break;
+}
+
int HardFork::get_voted_fork_index(uint64_t height) const
{
CRITICAL_REGION_LOCAL(lock);
uint32_t accumulated_votes = 0;
- for (unsigned int n = heights.size() - 1; n > current_fork_index; --n) {
+ for (int n = heights.size() - 1; n >= 0; --n) {
uint8_t v = heights[n].version;
accumulated_votes += last_versions[v];
uint32_t threshold = (window_size * heights[n].threshold + 99) / 100;
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
index a63a66976..123978b12 100644
--- a/src/cryptonote_basic/hardfork.h
+++ b/src/cryptonote_basic/hardfork.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -150,6 +150,16 @@ namespace cryptonote
bool reorganize_from_chain_height(uint64_t height);
/**
+ * @brief called when one or more blocks are popped from the blockchain
+ *
+ * The current fork will be updated by looking up the db,
+ * which is much cheaper than recomputing everything
+ *
+ * @param new_chain_height the height of the chain after popping
+ */
+ void on_block_popped(uint64_t new_chain_height);
+
+ /**
* @brief returns current state at the given time
*
* Based on the approximate time of the last known hard fork,
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
index f4de2ed7e..6628c8448 100644
--- a/src/cryptonote_basic/miner.cpp
+++ b/src/cryptonote_basic/miner.cpp
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -73,6 +73,9 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "miner"
+#define AUTODETECT_WINDOW 10 // seconds
+#define AUTODETECT_GAIN_THRESHOLD 1.02f // 2%
+
using namespace epee;
#include "miner.h"
@@ -108,6 +111,7 @@ namespace cryptonote
m_starter_nonce(0),
m_last_hr_merge_time(0),
m_hashes(0),
+ m_total_hashes(0),
m_do_print_hashrate(false),
m_do_mining(false),
m_current_hash_rate(0),
@@ -115,7 +119,8 @@ namespace cryptonote
m_min_idle_seconds(BACKGROUND_MINING_DEFAULT_MIN_IDLE_INTERVAL_IN_SECONDS),
m_idle_threshold(BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE),
m_mining_target(BACKGROUND_MINING_DEFAULT_MINING_TARGET_PERCENTAGE),
- m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS)
+ m_miner_extra_sleep(BACKGROUND_MINING_DEFAULT_MINER_EXTRA_SLEEP_MILLIS),
+ m_block_reward(0)
{
}
@@ -126,12 +131,13 @@ namespace cryptonote
catch (...) { /* ignore */ }
}
//-----------------------------------------------------------------------------------------------------
- bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
+ bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height, uint64_t block_reward)
{
CRITICAL_REGION_LOCAL(m_template_lock);
m_template = bl;
m_diffic = di;
m_height = height;
+ m_block_reward = block_reward;
++m_template_no;
m_starter_nonce = crypto::rand<uint32_t>();
return true;
@@ -163,7 +169,7 @@ namespace cryptonote
LOG_ERROR("Failed to get_block_template(), stopping mining");
return false;
}
- set_block_template(bl, di, height);
+ set_block_template(bl, di, height, expected_reward);
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -178,7 +184,12 @@ namespace cryptonote
merge_hr();
return true;
});
-
+
+ m_autodetect_interval.do_call([&](){
+ update_autodetection();
+ return true;
+ });
+
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -209,6 +220,60 @@ namespace cryptonote
m_hashes = 0;
}
//-----------------------------------------------------------------------------------------------------
+ void miner::update_autodetection()
+ {
+ if (m_threads_autodetect.empty())
+ return;
+
+ uint64_t now = epee::misc_utils::get_ns_count();
+ uint64_t dt = now - m_threads_autodetect.back().first;
+ if (dt < AUTODETECT_WINDOW * 1000000000ull)
+ return;
+
+ // work out how many more hashes we got
+ m_threads_autodetect.back().first = dt;
+ uint64_t dh = m_total_hashes - m_threads_autodetect.back().second;
+ m_threads_autodetect.back().second = dh;
+ float hs = dh / (dt / (float)1000000000);
+ MGINFO("Mining autodetection: " << m_threads_autodetect.size() << " threads: " << hs << " H/s");
+
+ // when we don't increase by at least 2%, stop, otherwise check next
+ // if N and N+1 have mostly the same hash rate, we want to "lighter" one
+ bool found = false;
+ if (m_threads_autodetect.size() > 1)
+ {
+ int previdx = m_threads_autodetect.size() - 2;
+ float previous_hs = m_threads_autodetect[previdx].second / (m_threads_autodetect[previdx].first / (float)1000000000);
+ if (previous_hs > 0 && hs / previous_hs < AUTODETECT_GAIN_THRESHOLD)
+ {
+ m_threads_total = m_threads_autodetect.size() - 1;
+ m_threads_autodetect.clear();
+ MGINFO("Optimal number of threads seems to be " << m_threads_total);
+ found = true;
+ }
+ }
+
+ if (!found)
+ {
+ // setup one more thread
+ m_threads_autodetect.push_back({now, m_total_hashes});
+ m_threads_total = m_threads_autodetect.size();
+ }
+
+ // restart all threads
+ {
+ CRITICAL_REGION_LOCAL(m_threads_lock);
+ boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
+ for(boost::thread& th: m_threads)
+ th.join();
+ m_threads.clear();
+ }
+ boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
+ boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);
+ for(size_t i = 0; i != m_threads_total; i++)
+ m_threads.push_back(boost::thread(m_attrs, boost::bind(&miner::worker_thread, this)));
+ }
+ //-----------------------------------------------------------------------------------------------------
void miner::init_options(boost::program_options::options_description& desc)
{
command_line::add_arg(desc, arg_extra_messages);
@@ -242,7 +307,8 @@ namespace cryptonote
}
m_config_folder_path = boost::filesystem::path(command_line::get_arg(vm, arg_extra_messages)).parent_path().string();
m_config = AUTO_VAL_INIT(m_config);
- epee::serialization::load_t_from_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
+ const std::string filename = m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME;
+ CHECK_AND_ASSERT_MES(epee::serialization::load_t_from_json_file(m_config, filename), false, "Failed to load data from " << filename);
MINFO("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
}
@@ -295,8 +361,16 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------------
bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background, bool ignore_battery)
{
+ m_block_reward = 0;
m_mine_address = adr;
m_threads_total = static_cast<uint32_t>(threads_count);
+ if (threads_count == 0)
+ {
+ m_threads_autodetect.clear();
+ m_threads_autodetect.push_back({epee::misc_utils::get_ns_count(), m_total_hashes});
+ m_threads_total = 1;
+ }
+ m_attrs = attrs;
m_starter_nonce = crypto::rand<uint32_t>();
CRITICAL_REGION_LOCAL(m_threads_lock);
if(is_mining())
@@ -318,12 +392,15 @@ namespace cryptonote
set_is_background_mining_enabled(do_background);
set_ignore_battery(ignore_battery);
- for(size_t i = 0; i != threads_count; i++)
+ for(size_t i = 0; i != m_threads_total; i++)
{
m_threads.push_back(boost::thread(attrs, boost::bind(&miner::worker_thread, this)));
}
- LOG_PRINT_L0("Mining has started with " << threads_count << " threads, good luck!" );
+ if (threads_count == 0)
+ MINFO("Mining has started, autodetecting optimal number of threads, good luck!" );
+ else
+ MINFO("Mining has started with " << threads_count << " threads, good luck!" );
if( get_is_background_mining_enabled() )
{
@@ -360,7 +437,7 @@ namespace cryptonote
if (!is_mining())
{
- MDEBUG("Not mining - nothing to stop" );
+ MTRACE("Not mining - nothing to stop" );
return true;
}
@@ -381,6 +458,7 @@ namespace cryptonote
MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
m_threads.clear();
+ m_threads_autodetect.clear();
return true;
}
//-----------------------------------------------------------------------------------------------------
@@ -506,6 +584,7 @@ namespace cryptonote
}
nonce+=m_threads_total;
++m_hashes;
+ ++m_total_hashes;
}
slow_hash_free_state();
MGINFO("Miner thread stopped ["<< th_local_index << "]");
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
index e16d9f3b8..08b1bd7f1 100644
--- a/src/cryptonote_basic/miner.h
+++ b/src/cryptonote_basic/miner.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
@@ -61,7 +61,7 @@ namespace cryptonote
~miner();
bool init(const boost::program_options::variables_map& vm, network_type nettype);
static void init_options(boost::program_options::options_description& desc);
- bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height);
+ bool set_block_template(const block& bl, const difficulty_type& diffic, uint64_t height, uint64_t block_reward);
bool on_block_chain_update();
bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs, bool do_background = false, bool ignore_battery = false);
uint64_t get_speed() const;
@@ -85,6 +85,7 @@ namespace cryptonote
bool set_idle_threshold(uint8_t idle_threshold);
uint8_t get_mining_target() const;
bool set_mining_target(uint8_t mining_target);
+ uint64_t get_block_reward() const { return m_block_reward; }
static constexpr uint8_t BACKGROUND_MINING_DEFAULT_IDLE_THRESHOLD_PERCENTAGE = 90;
static constexpr uint8_t BACKGROUND_MINING_MIN_IDLE_THRESHOLD_PERCENTAGE = 50;
@@ -103,6 +104,7 @@ namespace cryptonote
bool worker_thread();
bool request_block_template();
void merge_hr();
+ void update_autodetection();
struct miner_config
{
@@ -132,16 +134,20 @@ namespace cryptonote
account_public_address m_mine_address;
epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval;
epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;
+ epee::math_helper::once_a_time_seconds<1> m_autodetect_interval;
std::vector<blobdata> m_extra_messages;
miner_config m_config;
std::string m_config_folder_path;
std::atomic<uint64_t> m_last_hr_merge_time;
std::atomic<uint64_t> m_hashes;
+ std::atomic<uint64_t> m_total_hashes;
std::atomic<uint64_t> m_current_hash_rate;
epee::critical_section m_last_hash_rates_lock;
std::list<uint64_t> m_last_hash_rates;
bool m_do_print_hashrate;
bool m_do_mining;
+ std::vector<std::pair<uint64_t, uint64_t>> m_threads_autodetect;
+ boost::thread::attributes m_attrs;
// background mining stuffs ..
@@ -164,5 +170,6 @@ namespace cryptonote
static bool get_process_time(uint64_t& total_time);
static uint8_t get_percent_of_total(uint64_t some_time, uint64_t total_time);
static boost::logic::tribool on_battery_power();
+ std::atomic<uint64_t> m_block_reward;
};
}
diff --git a/src/cryptonote_basic/subaddress_index.h b/src/cryptonote_basic/subaddress_index.h
index 9b71448f9..99933e229 100644
--- a/src/cryptonote_basic/subaddress_index.h
+++ b/src/cryptonote_basic/subaddress_index.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017-2018, The Monero Project
+// Copyright (c) 2017-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h
index 009e35ebe..ecb4c6040 100644
--- a/src/cryptonote_basic/tx_extra.h
+++ b/src/cryptonote_basic/tx_extra.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//
diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h
index 8d2b633a2..36b63f254 100644
--- a/src/cryptonote_basic/verification_context.h
+++ b/src/cryptonote_basic/verification_context.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2014-2018, The Monero Project
+// Copyright (c) 2014-2019, The Monero Project
//
// All rights reserved.
//