aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_basic
diff options
context:
space:
mode:
authorkenshi84 <kenshi84@protonmail.ch>2017-01-27 00:07:23 +0900
committerkenshi84 <kenshi84@protonmail.ch>2017-02-08 22:45:15 +0900
commit8027ce0c75f882de0523e668defa0bc3c8564e96 (patch)
tree40066ffa7c7afb28907291c93863d8cfdb14920c /src/cryptonote_basic
parentMerge pull request #1679 (diff)
downloadmonero-8027ce0c75f882de0523e668defa0bc3c8564e96.tar.xz
extract some basic code from libcryptonote_core into libcryptonote_basic
Diffstat (limited to 'src/cryptonote_basic')
-rw-r--r--src/cryptonote_basic/CMakeLists.txt73
-rw-r--r--src/cryptonote_basic/account.cpp143
-rw-r--r--src/cryptonote_basic/account.h92
-rw-r--r--src/cryptonote_basic/account_boost_serialization.h57
-rw-r--r--src/cryptonote_basic/checkpoints.cpp368
-rw-r--r--src/cryptonote_basic/checkpoints.h217
-rw-r--r--src/cryptonote_basic/connection_context.h77
-rw-r--r--src/cryptonote_basic/cryptonote_basic.h397
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.cpp347
-rw-r--r--src/cryptonote_basic/cryptonote_basic_impl.h142
-rw-r--r--src/cryptonote_basic/cryptonote_boost_serialization.h301
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.cpp743
-rw-r--r--src/cryptonote_basic/cryptonote_format_utils.h213
-rw-r--r--src/cryptonote_basic/cryptonote_stat_info.h53
-rw-r--r--src/cryptonote_basic/difficulty.cpp165
-rw-r--r--src/cryptonote_basic/difficulty.h56
-rw-r--r--src/cryptonote_basic/hardfork.cpp416
-rw-r--r--src/cryptonote_basic/hardfork.h265
-rw-r--r--src/cryptonote_basic/miner.cpp414
-rw-r--r--src/cryptonote_basic/miner.h126
-rw-r--r--src/cryptonote_basic/tx_extra.h182
-rw-r--r--src/cryptonote_basic/verification_context.h61
22 files changed, 4908 insertions, 0 deletions
diff --git a/src/cryptonote_basic/CMakeLists.txt b/src/cryptonote_basic/CMakeLists.txt
new file mode 100644
index 000000000..ac8c53f95
--- /dev/null
+++ b/src/cryptonote_basic/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Copyright (c) 2014-2016, The Monero Project
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification, are
+# permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of
+# conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list
+# of conditions and the following disclaimer in the documentation and/or other
+# materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be
+# used to endorse or promote products derived from this software without specific
+# prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+set(cryptonote_basic_sources
+ account.cpp
+ checkpoints.cpp
+ cryptonote_basic_impl.cpp
+ cryptonote_format_utils.cpp
+ difficulty.cpp
+ miner.cpp
+ hardfork.cpp)
+
+set(cryptonote_basic_headers)
+
+set(cryptonote_basic_private_headers
+ account.h
+ account_boost_serialization.h
+ checkpoints.h
+ connection_context.h
+ cryptonote_basic.h
+ cryptonote_basic_impl.h
+ cryptonote_boost_serialization.h
+ cryptonote_format_utils.h
+ cryptonote_stat_info.h
+ difficulty.h
+ miner.h
+ tx_extra.h
+ verification_context.h
+ hardfork.h)
+
+monero_private_headers(cryptonote_basic
+ ${crypto_private_headers})
+monero_add_library(cryptonote_basic
+ ${cryptonote_basic_sources}
+ ${cryptonote_basic_headers}
+ ${cryptonote_basic_private_headers})
+target_link_libraries(cryptonote_basic
+ PUBLIC
+ common
+ crypto
+ ${Boost_DATE_TIME_LIBRARY}
+ ${Boost_PROGRAM_OPTIONS_LIBRARY}
+ ${Boost_SERIALIZATION_LIBRARY}
+ ${Boost_FILESYSTEM_LIBRARY}
+ ${Boost_SYSTEM_LIBRARY}
+ ${Boost_THREAD_LIBRARY}
+ PRIVATE
+ ${EXTRA_LIBRARIES})
diff --git a/src/cryptonote_basic/account.cpp b/src/cryptonote_basic/account.cpp
new file mode 100644
index 000000000..6d1a0a5e7
--- /dev/null
+++ b/src/cryptonote_basic/account.cpp
@@ -0,0 +1,143 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include <fstream>
+
+#include "include_base_utils.h"
+#include "account.h"
+#include "warnings.h"
+#include "crypto/crypto.h"
+extern "C"
+{
+#include "crypto/keccak.h"
+}
+#include "cryptonote_basic_impl.h"
+#include "cryptonote_format_utils.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "account"
+
+using namespace std;
+
+DISABLE_VS_WARNINGS(4244 4345)
+
+ namespace cryptonote
+{
+ //-----------------------------------------------------------------
+ account_base::account_base()
+ {
+ set_null();
+ }
+ //-----------------------------------------------------------------
+ void account_base::set_null()
+ {
+ m_keys = account_keys();
+ }
+ //-----------------------------------------------------------------
+ void account_base::forget_spend_key()
+ {
+ m_keys.m_spend_secret_key = crypto::secret_key();
+ }
+ //-----------------------------------------------------------------
+ crypto::secret_key account_base::generate(const crypto::secret_key& recovery_key, bool recover, bool two_random)
+ {
+ crypto::secret_key first = generate_keys(m_keys.m_account_address.m_spend_public_key, m_keys.m_spend_secret_key, recovery_key, recover);
+
+ // rng for generating second set of keys is hash of first rng. means only one set of electrum-style words needed for recovery
+ crypto::secret_key second;
+ keccak((uint8_t *)&m_keys.m_spend_secret_key, sizeof(crypto::secret_key), (uint8_t *)&second, sizeof(crypto::secret_key));
+
+ generate_keys(m_keys.m_account_address.m_view_public_key, m_keys.m_view_secret_key, second, two_random ? false : true);
+
+ struct tm timestamp = {0};
+ timestamp.tm_year = 2014 - 1900; // year 2014
+ timestamp.tm_mon = 6 - 1; // month june
+ timestamp.tm_mday = 8; // 8th of june
+ timestamp.tm_hour = 0;
+ timestamp.tm_min = 0;
+ timestamp.tm_sec = 0;
+
+ if (recover)
+ {
+ m_creation_timestamp = mktime(&timestamp);
+ if (m_creation_timestamp == (uint64_t)-1) // failure
+ m_creation_timestamp = 0; // lowest value
+ }
+ else
+ {
+ m_creation_timestamp = time(NULL);
+ }
+ return first;
+ }
+ //-----------------------------------------------------------------
+ void account_base::create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey)
+ {
+ m_keys.m_account_address = address;
+ m_keys.m_spend_secret_key = spendkey;
+ m_keys.m_view_secret_key = viewkey;
+
+ struct tm timestamp = {0};
+ timestamp.tm_year = 2014 - 1900; // year 2014
+ timestamp.tm_mon = 4 - 1; // month april
+ timestamp.tm_mday = 15; // 15th of april
+ timestamp.tm_hour = 0;
+ timestamp.tm_min = 0;
+ timestamp.tm_sec = 0;
+
+ m_creation_timestamp = mktime(&timestamp);
+ if (m_creation_timestamp == (uint64_t)-1) // failure
+ m_creation_timestamp = 0; // lowest value
+ }
+ //-----------------------------------------------------------------
+ void account_base::create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey)
+ {
+ crypto::secret_key fake;
+ memset(&fake, 0, sizeof(fake));
+ create_from_keys(address, fake, viewkey);
+ }
+ //-----------------------------------------------------------------
+ const account_keys& account_base::get_keys() const
+ {
+ return m_keys;
+ }
+ //-----------------------------------------------------------------
+ std::string account_base::get_public_address_str(bool testnet) const
+ {
+ //TODO: change this code into base 58
+ return get_account_address_as_str(testnet, m_keys.m_account_address);
+ }
+ //-----------------------------------------------------------------
+ std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const
+ {
+ //TODO: change this code into base 58
+ return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id);
+ }
+ //-----------------------------------------------------------------
+}
diff --git a/src/cryptonote_basic/account.h b/src/cryptonote_basic/account.h
new file mode 100644
index 000000000..b440adf33
--- /dev/null
+++ b/src/cryptonote_basic/account.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "cryptonote_basic.h"
+#include "crypto/crypto.h"
+#include "serialization/keyvalue_serialization.h"
+
+namespace cryptonote
+{
+
+ struct account_keys
+ {
+ account_public_address m_account_address;
+ crypto::secret_key m_spend_secret_key;
+ crypto::secret_key m_view_secret_key;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_account_address)
+ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_secret_key)
+ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_secret_key)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class account_base
+ {
+ public:
+ account_base();
+ crypto::secret_key generate(const crypto::secret_key& recovery_key = crypto::secret_key(), bool recover = false, bool two_random = false);
+ void create_from_keys(const cryptonote::account_public_address& address, const crypto::secret_key& spendkey, const crypto::secret_key& viewkey);
+ void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey);
+ const account_keys& get_keys() const;
+ std::string get_public_address_str(bool testnet) const;
+ std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const;
+
+ uint64_t get_createtime() const { return m_creation_timestamp; }
+ void set_createtime(uint64_t val) { m_creation_timestamp = val; }
+
+ bool load(const std::string& file_path);
+ bool store(const std::string& file_path);
+
+ void forget_spend_key();
+
+ template <class t_archive>
+ inline void serialize(t_archive &a, const unsigned int /*ver*/)
+ {
+ a & m_keys;
+ a & m_creation_timestamp;
+ }
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(m_keys)
+ KV_SERIALIZE(m_creation_timestamp)
+ END_KV_SERIALIZE_MAP()
+
+ private:
+ void set_null();
+ account_keys m_keys;
+ uint64_t m_creation_timestamp;
+ };
+}
diff --git a/src/cryptonote_basic/account_boost_serialization.h b/src/cryptonote_basic/account_boost_serialization.h
new file mode 100644
index 000000000..ff5554b49
--- /dev/null
+++ b/src/cryptonote_basic/account_boost_serialization.h
@@ -0,0 +1,57 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "account.h"
+#include "cryptonote_boost_serialization.h"
+
+//namespace cryptonote {
+namespace boost
+{
+ namespace serialization
+ {
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::account_keys &x, const boost::serialization::version_type ver)
+ {
+ a & x.m_account_address;
+ a & x.m_spend_secret_key;
+ a & x.m_view_secret_key;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::account_public_address &x, const boost::serialization::version_type ver)
+ {
+ a & x.m_spend_public_key;
+ a & x.m_view_public_key;
+ }
+
+ }
+}
diff --git a/src/cryptonote_basic/checkpoints.cpp b/src/cryptonote_basic/checkpoints.cpp
new file mode 100644
index 000000000..3cf804ede
--- /dev/null
+++ b/src/cryptonote_basic/checkpoints.cpp
@@ -0,0 +1,368 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "include_base_utils.h"
+
+using namespace epee;
+
+#include "checkpoints.h"
+
+#include "common/dns_utils.h"
+#include "include_base_utils.h"
+#include <sstream>
+#include <random>
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "checkpoints"
+
+namespace
+{
+ bool dns_records_match(const std::vector<std::string>& a, const std::vector<std::string>& b)
+ {
+ if (a.size() != b.size()) return false;
+
+ for (const auto& record_in_a : a)
+ {
+ bool ok = false;
+ for (const auto& record_in_b : b)
+ {
+ if (record_in_a == record_in_b)
+ {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) return false;
+ }
+
+ return true;
+ }
+} // anonymous namespace
+
+namespace cryptonote
+{
+ //---------------------------------------------------------------------------
+ checkpoints::checkpoints()
+ {
+ }
+ //---------------------------------------------------------------------------
+ bool checkpoints::add_checkpoint(uint64_t height, const std::string& hash_str)
+ {
+ crypto::hash h = null_hash;
+ bool r = epee::string_tools::parse_tpod_from_hex_string(hash_str, h);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse checkpoint hash string into binary representation!");
+
+ // return false if adding at a height we already have AND the hash is different
+ if (m_points.count(height))
+ {
+ CHECK_AND_ASSERT_MES(h == m_points[height], false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
+ }
+ m_points[height] = h;
+ return true;
+ }
+ //---------------------------------------------------------------------------
+ bool checkpoints::is_in_checkpoint_zone(uint64_t height) const
+ {
+ return !m_points.empty() && (height <= (--m_points.end())->first);
+ }
+ //---------------------------------------------------------------------------
+ bool checkpoints::check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const
+ {
+ auto it = m_points.find(height);
+ is_a_checkpoint = it != m_points.end();
+ if(!is_a_checkpoint)
+ return true;
+
+ if(it->second == h)
+ {
+ MINFO("CHECKPOINT PASSED FOR HEIGHT " << height << " " << h);
+ return true;
+ }else
+ {
+ MWARNING("CHECKPOINT FAILED FOR HEIGHT " << height << ". EXPECTED HASH: " << it->second << ", FETCHED HASH: " << h);
+ return false;
+ }
+ }
+ //---------------------------------------------------------------------------
+ bool checkpoints::check_block(uint64_t height, const crypto::hash& h) const
+ {
+ bool ignored;
+ return check_block(height, h, ignored);
+ }
+ //---------------------------------------------------------------------------
+ //FIXME: is this the desired behavior?
+ bool checkpoints::is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const
+ {
+ if (0 == block_height)
+ return false;
+
+ auto it = m_points.upper_bound(blockchain_height);
+ // Is blockchain_height before the first checkpoint?
+ if (it == m_points.begin())
+ return true;
+
+ --it;
+ uint64_t checkpoint_height = it->first;
+ return checkpoint_height < block_height;
+ }
+ //---------------------------------------------------------------------------
+ uint64_t checkpoints::get_max_height() const
+ {
+ std::map< uint64_t, crypto::hash >::const_iterator highest =
+ std::max_element( m_points.begin(), m_points.end(),
+ ( boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _1) <
+ boost::bind(&std::map< uint64_t, crypto::hash >::value_type::first, _2 ) ) );
+ return highest->first;
+ }
+ //---------------------------------------------------------------------------
+ const std::map<uint64_t, crypto::hash>& checkpoints::get_points() const
+ {
+ return m_points;
+ }
+
+ bool checkpoints::check_for_conflicts(const checkpoints& other) const
+ {
+ for (auto& pt : other.get_points())
+ {
+ if (m_points.count(pt.first))
+ {
+ CHECK_AND_ASSERT_MES(pt.second == m_points.at(pt.first), false, "Checkpoint at given height already exists, and hash for new checkpoint was different!");
+ }
+ }
+ return true;
+ }
+
+ bool checkpoints::init_default_checkpoints()
+ {
+ ADD_CHECKPOINT(1, "771fbcd656ec1464d3a02ead5e18644030007a0fc664c0a964d30922821a8148");
+ ADD_CHECKPOINT(10, "c0e3b387e47042f72d8ccdca88071ff96bff1ac7cde09ae113dbb7ad3fe92381");
+ ADD_CHECKPOINT(100, "ac3e11ca545e57c49fca2b4e8c48c03c23be047c43e471e1394528b1f9f80b2d");
+ ADD_CHECKPOINT(1000, "5acfc45acffd2b2e7345caf42fa02308c5793f15ec33946e969e829f40b03876");
+ ADD_CHECKPOINT(10000, "c758b7c81f928be3295d45e230646de8b852ec96a821eac3fea4daf3fcac0ca2");
+ ADD_CHECKPOINT(22231, "7cb10e29d67e1c069e6e11b17d30b809724255fee2f6868dc14cfc6ed44dfb25");
+ ADD_CHECKPOINT(29556, "53c484a8ed91e4da621bb2fa88106dbde426fe90d7ef07b9c1e5127fb6f3a7f6");
+ ADD_CHECKPOINT(50000, "0fe8758ab06a8b9cb35b7328fd4f757af530a5d37759f9d3e421023231f7b31c");
+ ADD_CHECKPOINT(80000, "a62dcd7b536f22e003ebae8726e9e7276f63d594e264b6f0cd7aab27b66e75e3");
+ ADD_CHECKPOINT(202612, "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698");
+ ADD_CHECKPOINT(202613, "e2aa337e78df1f98f462b3b1e560c6b914dec47b610698b7b7d1e3e86b6197c2");
+ ADD_CHECKPOINT(202614, "c29e3dc37d8da3e72e506e31a213a58771b24450144305bcba9e70fa4d6ea6fb");
+ ADD_CHECKPOINT(205000, "5d3d7a26e6dc7535e34f03def711daa8c263785f73ec1fadef8a45880fde8063");
+ ADD_CHECKPOINT(220000, "9613f455933c00e3e33ac315cc6b455ee8aa0c567163836858c2d9caff111553");
+ ADD_CHECKPOINT(230300, "bae7a80c46859db355556e3a9204a337ae8f24309926a1312323fdecf1920e61");
+ ADD_CHECKPOINT(230700, "93e631240ceac831da1aebfc5dac8f722c430463024763ebafa888796ceaeedf");
+ ADD_CHECKPOINT(231350, "b5add137199b820e1ea26640e5c3e121fd85faa86a1e39cf7e6cc097bdeb1131");
+ ADD_CHECKPOINT(232150, "955de8e6b6508af2c24f7334f97beeea651d78e9ade3ab18fec3763be3201aa8");
+ ADD_CHECKPOINT(249380, "654fb0a81ce3e5caf7e3264a70f447d4bd07586c08fa50f6638cc54da0a52b2d");
+ ADD_CHECKPOINT(460000, "75037a7aed3e765db96c75bcf908f59d690a5f3390baebb9edeafd336a1c4831");
+ ADD_CHECKPOINT(500000, "2428f0dbe49796be05ed81b347f53e1f7f44aed0abf641446ec2b94cae066b02");
+ ADD_CHECKPOINT(600000, "f5828ebf7d7d1cb61762c4dfe3ccf4ecab2e1aad23e8113668d981713b7a54c5");
+ ADD_CHECKPOINT(700000, "12be9b3d210b93f574d2526abb9c1ab2a881b479131fd0d4f7dac93875f503cd");
+ ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60");
+ ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337");
+ ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f");
+ ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721");
+ ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903");
+ ADD_CHECKPOINT(1150000, "1dd16f626d18e1e988490dfd06de5920e22629c972c58b4d8daddea0038627b2");
+ ADD_CHECKPOINT(1200000, "fa7d13a90850882060479d100141ff84286599ae39c3277c8ea784393f882d1f");
+
+
+ return true;
+ }
+
+ bool checkpoints::load_checkpoints_from_json(const std::string json_hashfile_fullpath)
+ {
+ boost::system::error_code errcode;
+ if (! (boost::filesystem::exists(json_hashfile_fullpath, errcode)))
+ {
+ LOG_PRINT_L1("Blockchain checkpoints file not found");
+ return true;
+ }
+
+ LOG_PRINT_L1("Adding checkpoints from blockchain hashfile");
+
+ uint64_t prev_max_height = get_max_height();
+ LOG_PRINT_L1("Hard-coded max checkpoint height is " << prev_max_height);
+ t_hash_json hashes;
+ epee::serialization::load_t_from_json_file(hashes, json_hashfile_fullpath);
+ for (std::vector<t_hashline>::const_iterator it = hashes.hashlines.begin(); it != hashes.hashlines.end(); )
+ {
+ uint64_t height;
+ height = it->height;
+ if (height <= prev_max_height) {
+ LOG_PRINT_L1("ignoring checkpoint height " << height);
+ } else {
+ std::string blockhash = it->hash;
+ LOG_PRINT_L1("Adding checkpoint height " << height << ", hash=" << blockhash);
+ ADD_CHECKPOINT(height, blockhash);
+ }
+ ++it;
+ }
+
+ return true;
+ }
+
+ bool checkpoints::load_checkpoints_from_dns(bool testnet)
+ {
+ // All four MoneroPulse domains have DNSSEC on and valid
+ static const std::vector<std::string> dns_urls = { "checkpoints.moneropulse.se"
+ , "checkpoints.moneropulse.org"
+ , "checkpoints.moneropulse.net"
+ , "checkpoints.moneropulse.co"
+ };
+
+ static const std::vector<std::string> testnet_dns_urls = { "testpoints.moneropulse.se"
+ , "testpoints.moneropulse.org"
+ , "testpoints.moneropulse.net"
+ , "testpoints.moneropulse.co"
+ };
+
+ std::vector<std::vector<std::string> > records;
+ records.resize(dns_urls.size());
+
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<int> dis(0, dns_urls.size() - 1);
+ size_t first_index = dis(gen);
+
+ bool avail, valid;
+ size_t cur_index = first_index;
+ do
+ {
+ std::string url;
+ if (testnet)
+ {
+ url = testnet_dns_urls[cur_index];
+ }
+ else
+ {
+ url = dns_urls[cur_index];
+ }
+
+ records[cur_index] = tools::DNSResolver::instance().get_txt_record(url, avail, valid);
+ if (!avail)
+ {
+ records[cur_index].clear();
+ LOG_PRINT_L2("DNSSEC not available for checkpoint update at URL: " << url << ", skipping.");
+ }
+ if (!valid)
+ {
+ records[cur_index].clear();
+ LOG_PRINT_L2("DNSSEC validation failed for checkpoint update at URL: " << url << ", skipping.");
+ }
+
+ cur_index++;
+ if (cur_index == dns_urls.size())
+ {
+ cur_index = 0;
+ }
+ records[cur_index].clear();
+ } while (cur_index != first_index);
+
+ size_t num_valid_records = 0;
+
+ for( const auto& record_set : records)
+ {
+ if (record_set.size() != 0)
+ {
+ num_valid_records++;
+ }
+ }
+
+ if (num_valid_records < 2)
+ {
+ LOG_PRINT_L0("WARNING: no two valid MoneroPulse DNS checkpoint records were received");
+ return true;
+ }
+
+ int good_records_index = -1;
+ for (size_t i = 0; i < records.size() - 1; ++i)
+ {
+ if (records[i].size() == 0) continue;
+
+ for (size_t j = i + 1; j < records.size(); ++j)
+ {
+ if (dns_records_match(records[i], records[j]))
+ {
+ good_records_index = i;
+ break;
+ }
+ }
+ if (good_records_index >= 0) break;
+ }
+
+ if (good_records_index < 0)
+ {
+ LOG_PRINT_L0("WARNING: no two MoneroPulse DNS checkpoint records matched");
+ return true;
+ }
+
+ for (auto& record : records[good_records_index])
+ {
+ auto pos = record.find(":");
+ if (pos != std::string::npos)
+ {
+ uint64_t height;
+ crypto::hash hash;
+
+ // parse the first part as uint64_t,
+ // if this fails move on to the next record
+ std::stringstream ss(record.substr(0, pos));
+ if (!(ss >> height))
+ {
+ continue;
+ }
+
+ // parse the second part as crypto::hash,
+ // if this fails move on to the next record
+ std::string hashStr = record.substr(pos + 1);
+ if (!epee::string_tools::parse_tpod_from_hex_string(hashStr, hash))
+ {
+ continue;
+ }
+
+ ADD_CHECKPOINT(height, hashStr);
+ }
+ }
+ return true;
+ }
+
+ bool checkpoints::load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet, bool dns)
+ {
+ bool result;
+
+ result = load_checkpoints_from_json(json_hashfile_fullpath);
+ if (dns)
+ {
+ result &= load_checkpoints_from_dns(testnet);
+ }
+
+ return result;
+ }
+}
diff --git a/src/cryptonote_basic/checkpoints.h b/src/cryptonote_basic/checkpoints.h
new file mode 100644
index 000000000..71727753e
--- /dev/null
+++ b/src/cryptonote_basic/checkpoints.h
@@ -0,0 +1,217 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+#include <map>
+#include <vector>
+#include "cryptonote_basic_impl.h"
+#include "misc_log_ex.h"
+#include "storages/portable_storage_template_helper.h" // epee json include
+
+#define ADD_CHECKPOINT(h, hash) CHECK_AND_ASSERT(add_checkpoint(h, hash), false);
+#define JSON_HASH_FILE_NAME "checkpoints.json"
+
+
+namespace cryptonote
+{
+ /**
+ * @brief A container for blockchain checkpoints
+ *
+ * A checkpoint is a pre-defined hash for the block at a given height.
+ * Some of these are compiled-in, while others can be loaded at runtime
+ * either from a json file or via DNS from a checkpoint-hosting server.
+ */
+ class checkpoints
+ {
+ public:
+
+ /**
+ * @brief default constructor
+ */
+ checkpoints();
+
+ /**
+ * @brief adds a checkpoint to the container
+ *
+ * @param height the height of the block the checkpoint is for
+ * @param hash_str the hash of the block, as a string
+ *
+ * @return false if parsing the hash fails, or if the height is a duplicate
+ * AND the existing checkpoint hash does not match the new one,
+ * otherwise returns true
+ */
+ bool add_checkpoint(uint64_t height, const std::string& hash_str);
+
+ /**
+ * @brief checks if there is a checkpoint in the future
+ *
+ * This function checks if the height passed is lower than the highest
+ * checkpoint.
+ *
+ * @param height the height to check against
+ *
+ * @return false if no checkpoints, otherwise returns whether or not
+ * the height passed is lower than the highest checkpoint.
+ */
+ bool is_in_checkpoint_zone(uint64_t height) const;
+
+ /**
+ * @brief checks if the given height and hash agree with the checkpoints
+ *
+ * This function checks if the given height and hash exist in the
+ * checkpoints container. If so, it returns whether or not the passed
+ * parameters match the stored values.
+ *
+ * @param height the height to be checked
+ * @param h the hash to be checked
+ * @param is_a_checkpoint return-by-reference if there is a checkpoint at the given height
+ *
+ * @return true if there is no checkpoint at the given height,
+ * true if the passed parameters match the stored checkpoint,
+ * false otherwise
+ */
+ bool check_block(uint64_t height, const crypto::hash& h, bool& is_a_checkpoint) const;
+
+ /**
+ * @overload
+ */
+ bool check_block(uint64_t height, const crypto::hash& h) const;
+
+ /**
+ * @brief checks if alternate chain blocks should be kept for a given height
+ *
+ * this basically says if the blockchain is smaller than the first
+ * checkpoint then alternate blocks are allowed. Alternatively, if the
+ * last checkpoint *before* the end of the current chain is also before
+ * the block to be added, then this is fine.
+ *
+ * @param blockchain_height the current blockchain height
+ * @param block_height the height of the block to be added as alternate
+ *
+ * @return true if alternate blocks are allowed given the parameters,
+ * otherwise false
+ */
+ bool is_alternative_block_allowed(uint64_t blockchain_height, uint64_t block_height) const;
+
+ /**
+ * @brief gets the highest checkpoint height
+ *
+ * @return the height of the highest checkpoint
+ */
+ uint64_t get_max_height() const;
+
+ /**
+ * @brief gets the checkpoints container
+ *
+ * @return a const reference to the checkpoints container
+ */
+ const std::map<uint64_t, crypto::hash>& get_points() const;
+
+ /**
+ * @brief checks if our checkpoints container conflicts with another
+ *
+ * A conflict refers to a case where both checkpoint sets have a checkpoint
+ * for a specific height but their hashes for that height do not match.
+ *
+ * @param other the other checkpoints instance to check against
+ *
+ * @return false if any conflict is found, otherwise true
+ */
+ bool check_for_conflicts(const checkpoints& other) const;
+
+ /**
+ * @brief loads the default main chain checkpoints
+ *
+ * @return true unless adding a checkpoint fails
+ */
+ bool init_default_checkpoints();
+
+ /**
+ * @brief load new checkpoints
+ *
+ * Loads new checkpoints from the specified json file, as well as
+ * (optionally) from DNS.
+ *
+ * @param json_hashfile_fullpath path to the json checkpoints file
+ * @param testnet whether to load testnet checkpoints or mainnet
+ * @param dns whether or not to load DNS checkpoints
+ *
+ * @return true if loading successful and no conflicts
+ */
+ bool load_new_checkpoints(const std::string json_hashfile_fullpath, bool testnet=false, bool dns=true);
+
+ /**
+ * @brief load new checkpoints from json
+ *
+ * @param json_hashfile_fullpath path to the json checkpoints file
+ *
+ * @return true if loading successful and no conflicts
+ */
+ bool load_checkpoints_from_json(const std::string json_hashfile_fullpath);
+
+ /**
+ * @brief load new checkpoints from DNS
+ *
+ * @param testnet whether to load testnet checkpoints or mainnet
+ *
+ * @return true if loading successful and no conflicts
+ */
+ bool load_checkpoints_from_dns(bool testnet = false);
+
+ private:
+
+
+ /**
+ * @brief struct for loading a checkpoint from json
+ */
+ struct t_hashline
+ {
+ uint64_t height; //!< the height of the checkpoint
+ std::string hash; //!< the hash for the checkpoint
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(height)
+ KV_SERIALIZE(hash)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ /**
+ * @brief struct for loading many checkpoints from json
+ */
+ struct t_hash_json {
+ std::vector<t_hashline> hashlines; //!< the checkpoint lines from the file
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(hashlines)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ std::map<uint64_t, crypto::hash> m_points; //!< the checkpoints container
+
+ };
+}
diff --git a/src/cryptonote_basic/connection_context.h b/src/cryptonote_basic/connection_context.h
new file mode 100644
index 000000000..7e62e77b9
--- /dev/null
+++ b/src/cryptonote_basic/connection_context.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+#include <unordered_set>
+#include <atomic>
+#include "net/net_utils_base.h"
+#include "copyable_atomic.h"
+
+namespace cryptonote
+{
+
+ struct cryptonote_connection_context: public epee::net_utils::connection_context_base
+ {
+
+ enum state
+ {
+ state_befor_handshake = 0, //default state
+ state_synchronizing,
+ state_idle,
+ state_normal
+ };
+
+ state m_state;
+ std::list<crypto::hash> m_needed_objects;
+ std::unordered_set<crypto::hash> m_requested_objects;
+ uint64_t m_remote_blockchain_height;
+ uint64_t m_last_response_height;
+ epee::copyable_atomic m_callback_request_count; //in debug purpose: problem with double callback rise
+ //size_t m_score; TODO: add score calculations
+ };
+
+ inline std::string get_protocol_state_string(cryptonote_connection_context::state s)
+ {
+ switch (s)
+ {
+ case cryptonote_connection_context::state_befor_handshake:
+ return "state_befor_handshake";
+ case cryptonote_connection_context::state_synchronizing:
+ return "state_synchronizing";
+ case cryptonote_connection_context::state_idle:
+ return "state_idle";
+ case cryptonote_connection_context::state_normal:
+ return "state_normal";
+ default:
+ return "unknown";
+ }
+ }
+
+}
diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h
new file mode 100644
index 000000000..da069a21a
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_basic.h
@@ -0,0 +1,397 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <boost/variant.hpp>
+#include <boost/functional/hash/hash.hpp>
+#include <vector>
+#include <cstring> // memcmp
+#include <sstream>
+#include "serialization/serialization.h"
+#include "serialization/variant.h"
+#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 "string_tools.h"
+#include "cryptonote_config.h"
+#include "crypto/crypto.h"
+#include "crypto/hash.h"
+#include "misc_language.h"
+#include "tx_extra.h"
+#include "ringct/rctTypes.h"
+
+namespace cryptonote
+{
+
+ const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash);
+ const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8);
+ const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey);
+
+ typedef std::vector<crypto::signature> ring_signature;
+
+
+ /* outputs */
+
+ struct txout_to_script
+ {
+ std::vector<crypto::public_key> keys;
+ std::vector<uint8_t> script;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(keys)
+ FIELD(script)
+ END_SERIALIZE()
+ };
+
+ struct txout_to_scripthash
+ {
+ crypto::hash hash;
+ };
+
+ struct txout_to_key
+ {
+ txout_to_key() { }
+ txout_to_key(const crypto::public_key &_key) : key(_key) { }
+ crypto::public_key key;
+ };
+
+
+ /* inputs */
+
+ struct txin_gen
+ {
+ size_t height;
+
+ BEGIN_SERIALIZE_OBJECT()
+ VARINT_FIELD(height)
+ END_SERIALIZE()
+ };
+
+ struct txin_to_script
+ {
+ crypto::hash prev;
+ size_t prevout;
+ std::vector<uint8_t> sigset;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(prev)
+ VARINT_FIELD(prevout)
+ FIELD(sigset)
+ END_SERIALIZE()
+ };
+
+ struct txin_to_scripthash
+ {
+ crypto::hash prev;
+ size_t prevout;
+ txout_to_script script;
+ std::vector<uint8_t> sigset;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(prev)
+ VARINT_FIELD(prevout)
+ FIELD(script)
+ FIELD(sigset)
+ END_SERIALIZE()
+ };
+
+ struct txin_to_key
+ {
+ uint64_t amount;
+ std::vector<uint64_t> key_offsets;
+ crypto::key_image k_image; // double spending protection
+
+ BEGIN_SERIALIZE_OBJECT()
+ VARINT_FIELD(amount)
+ FIELD(key_offsets)
+ FIELD(k_image)
+ END_SERIALIZE()
+ };
+
+
+ typedef boost::variant<txin_gen, txin_to_script, txin_to_scripthash, txin_to_key> txin_v;
+
+ typedef boost::variant<txout_to_script, txout_to_scripthash, txout_to_key> txout_target_v;
+
+ //typedef std::pair<uint64_t, txout> out_t;
+ struct tx_out
+ {
+ uint64_t amount;
+ txout_target_v target;
+
+ BEGIN_SERIALIZE_OBJECT()
+ VARINT_FIELD(amount)
+ FIELD(target)
+ END_SERIALIZE()
+
+
+ };
+
+ class transaction_prefix
+ {
+
+ public:
+ // tx information
+ size_t version;
+ uint64_t unlock_time; //number of block (or time), used as a limitation like: spend this tx not early then block/time
+
+ std::vector<txin_v> vin;
+ std::vector<tx_out> vout;
+ //extra
+ std::vector<uint8_t> extra;
+
+ BEGIN_SERIALIZE()
+ VARINT_FIELD(version)
+ if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false;
+ VARINT_FIELD(unlock_time)
+ FIELD(vin)
+ FIELD(vout)
+ FIELD(extra)
+ END_SERIALIZE()
+
+ public:
+ transaction_prefix(){}
+ };
+
+ class transaction: public transaction_prefix
+ {
+ public:
+ std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
+ rct::rctSig rct_signatures;
+
+ transaction();
+ virtual ~transaction();
+ void set_null();
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELDS(*static_cast<transaction_prefix *>(this))
+
+ if (version == 1)
+ {
+ 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)
+ {
+ 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())
+ 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<txin_to_key>(vin[0]).key_offsets.size() - 1 : 0);
+ if (!r || !ar.stream().good()) return false;
+ ar.end_object();
+ }
+ }
+ }
+ END_SERIALIZE()
+
+ private:
+ static size_t get_signature_size(const txin_v& tx_in);
+ };
+
+
+ inline
+ transaction::transaction()
+ {
+ set_null();
+ }
+
+ inline
+ transaction::~transaction()
+ {
+ //set_null();
+ }
+
+ inline
+ void transaction::set_null()
+ {
+ version = 1;
+ unlock_time = 0;
+ vin.clear();
+ vout.clear();
+ extra.clear();
+ signatures.clear();
+ rct_signatures.type = rct::RCTTypeNull;
+ }
+
+ inline
+ size_t transaction::get_signature_size(const txin_v& tx_in)
+ {
+ struct txin_signature_size_visitor : public boost::static_visitor<size_t>
+ {
+ size_t operator()(const txin_gen& txin) const{return 0;}
+ size_t operator()(const txin_to_script& txin) const{return 0;}
+ size_t operator()(const txin_to_scripthash& txin) const{return 0;}
+ size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();}
+ };
+
+ return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
+ }
+
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct block_header
+ {
+ uint8_t major_version;
+ uint8_t minor_version; // now used as a voting mechanism, rather than how this particular block is built
+ uint64_t timestamp;
+ crypto::hash prev_id;
+ uint32_t nonce;
+
+ BEGIN_SERIALIZE()
+ VARINT_FIELD(major_version)
+ VARINT_FIELD(minor_version)
+ VARINT_FIELD(timestamp)
+ FIELD(prev_id)
+ FIELD(nonce)
+ END_SERIALIZE()
+ };
+
+ struct block: public block_header
+ {
+ transaction miner_tx;
+ std::vector<crypto::hash> tx_hashes;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELDS(*static_cast<block_header *>(this))
+ FIELD(miner_tx)
+ FIELD(tx_hashes)
+ END_SERIALIZE()
+ };
+
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct account_public_address
+ {
+ crypto::public_key m_spend_public_key;
+ crypto::public_key m_view_public_key;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(m_spend_public_key)
+ FIELD(m_view_public_key)
+ END_SERIALIZE()
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_spend_public_key)
+ KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(m_view_public_key)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ struct keypair
+ {
+ crypto::public_key pub;
+ crypto::secret_key sec;
+
+ static inline keypair generate()
+ {
+ keypair k;
+ generate_keys(k.pub, k.sec);
+ return k;
+ }
+ };
+ //---------------------------------------------------------------
+
+}
+
+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");
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.cpp b/src/cryptonote_basic/cryptonote_basic_impl.cpp
new file mode 100644
index 000000000..338210f01
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_basic_impl.cpp
@@ -0,0 +1,347 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "include_base_utils.h"
+using namespace epee;
+
+#include "cryptonote_basic_impl.h"
+#include "string_tools.h"
+#include "serialization/binary_utils.h"
+#include "serialization/vector.h"
+#include "cryptonote_format_utils.h"
+#include "cryptonote_config.h"
+#include "misc_language.h"
+#include "common/base58.h"
+#include "crypto/hash.h"
+#include "common/int-util.h"
+#include "common/dns_utils.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "cn"
+
+namespace cryptonote {
+
+ struct integrated_address {
+ account_public_address adr;
+ crypto::hash8 payment_id;
+
+ BEGIN_SERIALIZE_OBJECT()
+ FIELD(adr)
+ FIELD(payment_id)
+ END_SERIALIZE()
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(adr)
+ KV_SERIALIZE(payment_id)
+ END_KV_SERIALIZE_MAP()
+ };
+
+ /************************************************************************/
+ /* Cryptonote helper functions */
+ /************************************************************************/
+ //-----------------------------------------------------------------------------------------------
+ size_t get_max_block_size()
+ {
+ return CRYPTONOTE_MAX_BLOCK_SIZE;
+ }
+ //-----------------------------------------------------------------------------------------------
+ size_t get_max_tx_size()
+ {
+ return CRYPTONOTE_MAX_TX_SIZE;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint8_t version) {
+ static_assert(DIFFICULTY_TARGET_V2%60==0&&DIFFICULTY_TARGET_V1%60==0,"difficulty targets must be a multiple of 60");
+ const int target = version < 2 ? DIFFICULTY_TARGET_V1 : DIFFICULTY_TARGET_V2;
+ const int target_minutes = target / 60;
+ const int emission_speed_factor = EMISSION_SPEED_FACTOR_PER_MINUTE - (target_minutes-1);
+
+ uint64_t base_reward = (MONEY_SUPPLY - already_generated_coins) >> emission_speed_factor;
+ if (base_reward < FINAL_SUBSIDY_PER_MINUTE*target_minutes)
+ {
+ base_reward = FINAL_SUBSIDY_PER_MINUTE*target_minutes;
+ }
+
+ uint64_t full_reward_zone = version < 2 ? CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 : CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2;
+
+ //make it soft
+ if (median_size < full_reward_zone) {
+ median_size = full_reward_zone;
+ }
+
+ if (current_block_size <= median_size) {
+ reward = base_reward;
+ return true;
+ }
+
+ if(current_block_size > 2 * median_size) {
+ MERROR("Block cumulative size is too big: " << current_block_size << ", expected less than " << 2 * median_size);
+ return false;
+ }
+
+ assert(median_size < std::numeric_limits<uint32_t>::max());
+ assert(current_block_size < std::numeric_limits<uint32_t>::max());
+
+ uint64_t product_hi;
+ // BUGFIX: 32-bit saturation bug (e.g. ARM7), the result was being
+ // treated as 32-bit by default.
+ uint64_t multiplicand = 2 * median_size - current_block_size;
+ multiplicand *= current_block_size;
+ uint64_t product_lo = mul128(base_reward, multiplicand, &product_hi);
+
+ uint64_t reward_hi;
+ uint64_t reward_lo;
+ div128_32(product_hi, product_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
+ div128_32(reward_hi, reward_lo, static_cast<uint32_t>(median_size), &reward_hi, &reward_lo);
+ assert(0 == reward_hi);
+ assert(reward_lo < base_reward);
+
+ reward = reward_lo;
+ return true;
+ }
+ //------------------------------------------------------------------------------------
+ uint8_t get_account_address_checksum(const public_address_outer_blob& bl)
+ {
+ const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
+ uint8_t summ = 0;
+ for(size_t i = 0; i!= sizeof(public_address_outer_blob)-1; i++)
+ summ += pbuf[i];
+
+ return summ;
+ }
+ //------------------------------------------------------------------------------------
+ uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl)
+ {
+ const unsigned char* pbuf = reinterpret_cast<const unsigned char*>(&bl);
+ uint8_t summ = 0;
+ for(size_t i = 0; i!= sizeof(public_integrated_address_outer_blob)-1; i++)
+ summ += pbuf[i];
+
+ return summ;
+ }
+ //-----------------------------------------------------------------------
+ std::string get_account_address_as_str(
+ bool testnet
+ , account_public_address const & adr
+ )
+ {
+ uint64_t address_prefix = testnet ?
+ config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
+
+ return tools::base58::encode_addr(address_prefix, t_serializable_object_to_blob(adr));
+ }
+ //-----------------------------------------------------------------------
+ std::string get_account_integrated_address_as_str(
+ bool testnet
+ , account_public_address const & adr
+ , crypto::hash8 const & payment_id
+ )
+ {
+ uint64_t integrated_address_prefix = testnet ?
+ config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
+
+ integrated_address iadr = {
+ adr, payment_id
+ };
+ return tools::base58::encode_addr(integrated_address_prefix, t_serializable_object_to_blob(iadr));
+ }
+ //-----------------------------------------------------------------------
+ bool is_coinbase(const transaction& tx)
+ {
+ if(tx.vin.size() != 1)
+ return false;
+
+ if(tx.vin[0].type() != typeid(txin_gen))
+ return false;
+
+ return true;
+ }
+ //-----------------------------------------------------------------------
+ bool get_account_integrated_address_from_str(
+ account_public_address& adr
+ , bool& has_payment_id
+ , crypto::hash8& payment_id
+ , bool testnet
+ , std::string const & str
+ )
+ {
+ uint64_t address_prefix = testnet ?
+ config::testnet::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX;
+ uint64_t integrated_address_prefix = testnet ?
+ config::testnet::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX : config::CRYPTONOTE_PUBLIC_INTEGRATED_ADDRESS_BASE58_PREFIX;
+
+ if (2 * sizeof(public_address_outer_blob) != str.size())
+ {
+ blobdata data;
+ uint64_t prefix;
+ if (!tools::base58::decode_addr(str, prefix, data))
+ {
+ LOG_PRINT_L2("Invalid address format");
+ return false;
+ }
+
+ if (integrated_address_prefix == prefix)
+ {
+ has_payment_id = true;
+ }
+ else if (address_prefix == prefix)
+ {
+ has_payment_id = false;
+ }
+ else {
+ LOG_PRINT_L1("Wrong address prefix: " << prefix << ", expected " << address_prefix << " or " << integrated_address_prefix);
+ return false;
+ }
+
+ if (has_payment_id)
+ {
+ integrated_address iadr;
+ if (!::serialization::parse_binary(data, iadr))
+ {
+ LOG_PRINT_L1("Account public address keys can't be parsed");
+ return false;
+ }
+ adr = iadr.adr;
+ payment_id = iadr.payment_id;
+ }
+ else
+ {
+ if (!::serialization::parse_binary(data, adr))
+ {
+ LOG_PRINT_L1("Account public address keys can't be parsed");
+ return false;
+ }
+ }
+
+ if (!crypto::check_key(adr.m_spend_public_key) || !crypto::check_key(adr.m_view_public_key))
+ {
+ LOG_PRINT_L1("Failed to validate address keys");
+ return false;
+ }
+ }
+ else
+ {
+ // Old address format
+ std::string buff;
+ if(!string_tools::parse_hexstr_to_binbuff(str, buff))
+ return false;
+
+ if(buff.size()!=sizeof(public_address_outer_blob))
+ {
+ LOG_PRINT_L1("Wrong public address size: " << buff.size() << ", expected size: " << sizeof(public_address_outer_blob));
+ return false;
+ }
+
+ public_address_outer_blob blob = *reinterpret_cast<const public_address_outer_blob*>(buff.data());
+
+
+ if(blob.m_ver > CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER)
+ {
+ LOG_PRINT_L1("Unknown version of public address: " << blob.m_ver << ", expected " << CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER);
+ return false;
+ }
+
+ if(blob.check_sum != get_account_address_checksum(blob))
+ {
+ LOG_PRINT_L1("Wrong public address checksum");
+ return false;
+ }
+
+ //we success
+ adr = blob.m_address;
+ has_payment_id = false;
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------
+ bool get_account_address_from_str(
+ account_public_address& adr
+ , bool testnet
+ , std::string const & str
+ )
+ {
+ bool has_payment_id;
+ crypto::hash8 payment_id;
+ return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str);
+ }
+ //--------------------------------------------------------------------------------
+ bool get_account_address_from_str_or_url(
+ cryptonote::account_public_address& address
+ , bool& has_payment_id
+ , crypto::hash8& payment_id
+ , bool testnet
+ , const std::string& str_or_url
+ )
+ {
+ if (get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, str_or_url))
+ return true;
+ bool dnssec_valid;
+ std::string address_str = tools::dns_utils::get_account_address_as_str_from_url(str_or_url, dnssec_valid);
+ return !address_str.empty() &&
+ get_account_integrated_address_from_str(address, has_payment_id, payment_id, testnet, address_str);
+ }
+ //--------------------------------------------------------------------------------
+ bool get_account_address_from_str_or_url(
+ cryptonote::account_public_address& address
+ , bool testnet
+ , const std::string& str_or_url
+ )
+ {
+ bool has_payment_id;
+ crypto::hash8 payment_id;
+ return get_account_address_from_str_or_url(address, has_payment_id, payment_id, testnet, str_or_url);
+ }
+ //--------------------------------------------------------------------------------
+ bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b) {
+ return cryptonote::get_transaction_hash(a) == cryptonote::get_transaction_hash(b);
+ }
+
+ bool operator ==(const cryptonote::block& a, const cryptonote::block& b) {
+ return cryptonote::get_block_hash(a) == cryptonote::get_block_hash(b);
+ }
+}
+
+//--------------------------------------------------------------------------------
+bool parse_hash256(const std::string str_hash, crypto::hash& hash)
+{
+ std::string buf;
+ bool res = epee::string_tools::parse_hexstr_to_binbuff(str_hash, buf);
+ if (!res || buf.size() != sizeof(crypto::hash))
+ {
+ std::cout << "invalid hash format: <" << str_hash << '>' << std::endl;
+ return false;
+ }
+ else
+ {
+ buf.copy(reinterpret_cast<char *>(&hash), sizeof(crypto::hash));
+ return true;
+ }
+}
diff --git a/src/cryptonote_basic/cryptonote_basic_impl.h b/src/cryptonote_basic/cryptonote_basic_impl.h
new file mode 100644
index 000000000..5703a7d75
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_basic_impl.h
@@ -0,0 +1,142 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include "cryptonote_basic.h"
+#include "crypto/crypto.h"
+#include "crypto/hash.h"
+
+
+namespace cryptonote {
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ template<class t_array>
+ struct array_hasher: std::unary_function<t_array&, std::size_t>
+ {
+ std::size_t operator()(const t_array& val) const
+ {
+ return boost::hash_range(&val.data[0], &val.data[sizeof(val.data)]);
+ }
+ };
+
+
+#pragma pack(push, 1)
+ struct public_address_outer_blob
+ {
+ uint8_t m_ver;
+ account_public_address m_address;
+ uint8_t check_sum;
+ };
+ struct public_integrated_address_outer_blob
+ {
+ uint8_t m_ver;
+ account_public_address m_address;
+ crypto::hash8 payment_id;
+ uint8_t check_sum;
+ };
+#pragma pack (pop)
+
+
+ /************************************************************************/
+ /* Cryptonote helper functions */
+ /************************************************************************/
+ size_t get_max_block_size();
+ size_t get_max_tx_size();
+ bool get_block_reward(size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint8_t version);
+ uint8_t get_account_address_checksum(const public_address_outer_blob& bl);
+ uint8_t get_account_integrated_address_checksum(const public_integrated_address_outer_blob& bl);
+
+ std::string get_account_address_as_str(
+ bool testnet
+ , const account_public_address& adr
+ );
+
+ std::string get_account_integrated_address_as_str(
+ bool testnet
+ , const account_public_address& adr
+ , const crypto::hash8& payment_id
+ );
+
+ bool get_account_integrated_address_from_str(
+ account_public_address& adr
+ , bool& has_payment_id
+ , crypto::hash8& payment_id
+ , bool testnet
+ , const std::string& str
+ );
+
+ bool get_account_address_from_str(
+ account_public_address& adr
+ , bool testnet
+ , const std::string& str
+ );
+
+ bool get_account_address_from_str_or_url(
+ cryptonote::account_public_address& address
+ , bool& has_payment_id
+ , crypto::hash8& payment_id
+ , bool testnet
+ , const std::string& str_or_url
+ );
+
+ bool get_account_address_from_str_or_url(
+ cryptonote::account_public_address& address
+ , bool testnet
+ , const std::string& str_or_url
+ );
+
+ bool is_coinbase(const transaction& tx);
+
+ bool operator ==(const cryptonote::transaction& a, const cryptonote::transaction& b);
+ bool operator ==(const cryptonote::block& a, const cryptonote::block& b);
+}
+
+template <class T>
+std::ostream &print256(std::ostream &o, const T &v) {
+ return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
+}
+template <class T>
+std::ostream &print64(std::ostream &o, const T &v) {
+ return o << "<" << epee::string_tools::pod_to_hex(v) << ">";
+}
+
+bool parse_hash256(const std::string str_hash, crypto::hash& hash);
+
+namespace crypto {
+ inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); }
+ inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { return print64(o, v); }
+}
diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h
new file mode 100644
index 000000000..409b9798c
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_boost_serialization.h
@@ -0,0 +1,301 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <boost/serialization/vector.hpp>
+#include <boost/serialization/utility.hpp>
+#include <boost/serialization/variant.hpp>
+#include <boost/serialization/set.hpp>
+#include <boost/serialization/map.hpp>
+#include <boost/serialization/is_bitwise_serializable.hpp>
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/portable_binary_iarchive.hpp>
+#include <boost/archive/portable_binary_oarchive.hpp>
+#include "cryptonote_basic.h"
+#include "common/unordered_containers_boost_serialization.h"
+#include "crypto/crypto.h"
+#include "ringct/rctTypes.h"
+#include "ringct/rctOps.h"
+
+//namespace cryptonote {
+namespace boost
+{
+ namespace serialization
+ {
+
+ //---------------------------------------------------
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
+ }
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
+ }
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
+ }
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
+ }
+ template <class Archive>
+ inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txout_to_script &x, const boost::serialization::version_type ver)
+ {
+ a & x.keys;
+ a & x.script;
+ }
+
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txout_to_key &x, const boost::serialization::version_type ver)
+ {
+ a & x.key;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txout_to_scripthash &x, const boost::serialization::version_type ver)
+ {
+ a & x.hash;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txin_gen &x, const boost::serialization::version_type ver)
+ {
+ a & x.height;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txin_to_script &x, const boost::serialization::version_type ver)
+ {
+ a & x.prev;
+ a & x.prevout;
+ a & x.sigset;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txin_to_scripthash &x, const boost::serialization::version_type ver)
+ {
+ a & x.prev;
+ a & x.prevout;
+ a & x.script;
+ a & x.sigset;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::txin_to_key &x, const boost::serialization::version_type ver)
+ {
+ a & x.amount;
+ a & x.key_offsets;
+ a & x.k_image;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::tx_out &x, const boost::serialization::version_type ver)
+ {
+ a & x.amount;
+ a & x.target;
+ }
+
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::transaction_prefix &x, const boost::serialization::version_type ver)
+ {
+ a & x.version;
+ a & x.unlock_time;
+ a & x.vin;
+ a & x.vout;
+ a & x.extra;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::transaction &x, const boost::serialization::version_type ver)
+ {
+ a & x.version;
+ a & x.unlock_time;
+ a & x.vin;
+ a & x.vout;
+ a & x.extra;
+ if (x.version == 1)
+ {
+ a & x.signatures;
+ }
+ else
+ {
+ a & (rct::rctSigBase&)x.rct_signatures;
+ if (x.rct_signatures.type != rct::RCTTypeNull)
+ a & x.rct_signatures.p;
+ }
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, cryptonote::block &b, const boost::serialization::version_type ver)
+ {
+ a & b.major_version;
+ a & b.minor_version;
+ a & b.timestamp;
+ a & b.prev_id;
+ a & b.nonce;
+ //------------------
+ a & b.miner_tx;
+ a & b.tx_hashes;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::key &x, const boost::serialization::version_type ver)
+ {
+ a & reinterpret_cast<char (&)[sizeof(rct::key)]>(x);
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::ctkey &x, const boost::serialization::version_type ver)
+ {
+ a & x.dest;
+ a & x.mask;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::rangeSig &x, const boost::serialization::version_type ver)
+ {
+ a & x.asig;
+ a & x.Ci;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
+ {
+ a & x.s0;
+ a & x.s1;
+ a & x.ee;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::mgSig &x, const boost::serialization::version_type ver)
+ {
+ a & x.ss;
+ a & x.cc;
+ // a & x.II; // not serialized, we can recover it from the tx vin
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::ecdhTuple &x, const boost::serialization::version_type ver)
+ {
+ a & x.mask;
+ a & x.amount;
+ // a & x.senderPk; // not serialized, as we do not use it in monero currently
+ }
+
+ template <class Archive>
+ inline typename std::enable_if<Archive::is_loading::value, void>::type serializeOutPk(Archive &a, rct::ctkeyV &outPk_, const boost::serialization::version_type ver)
+ {
+ rct::keyV outPk;
+ a & outPk;
+ outPk_.resize(outPk.size());
+ for (size_t n = 0; n < outPk_.size(); ++n)
+ {
+ outPk_[n].dest = rct::identity();
+ outPk_[n].mask = outPk[n];
+ }
+ }
+
+ template <class Archive>
+ inline typename std::enable_if<Archive::is_saving::value, void>::type serializeOutPk(Archive &a, rct::ctkeyV &outPk_, const boost::serialization::version_type ver)
+ {
+ rct::keyV outPk(outPk_.size());
+ for (size_t n = 0; n < outPk_.size(); ++n)
+ outPk[n] = outPk_[n].mask;
+ a & outPk;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::rctSigBase &x, const boost::serialization::version_type ver)
+ {
+ a & x.type;
+ if (x.type == rct::RCTTypeNull)
+ return;
+ if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
+ 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
+ if (x.type == rct::RCTTypeSimple)
+ a & x.pseudoOuts;
+ a & x.ecdhInfo;
+ serializeOutPk(a, x.outPk, ver);
+ a & x.txnFee;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::rctSigPrunable &x, const boost::serialization::version_type ver)
+ {
+ a & x.rangeSigs;
+ a & x.MGs;
+ }
+
+ template <class Archive>
+ inline void serialize(Archive &a, rct::rctSig &x, const boost::serialization::version_type ver)
+ {
+ a & x.type;
+ if (x.type == rct::RCTTypeNull)
+ return;
+ if (x.type != rct::RCTTypeFull && x.type != rct::RCTTypeSimple)
+ 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
+ if (x.type == rct::RCTTypeSimple)
+ a & x.pseudoOuts;
+ a & x.ecdhInfo;
+ serializeOutPk(a, x.outPk, ver);
+ a & x.txnFee;
+ //--------------
+ a & x.p.rangeSigs;
+ a & x.p.MGs;
+ }
+}
+}
+
+//}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp
new file mode 100644
index 000000000..2364663f3
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_format_utils.cpp
@@ -0,0 +1,743 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include "include_base_utils.h"
+using namespace epee;
+
+#include "cryptonote_format_utils.h"
+#include "cryptonote_config.h"
+#include "crypto/crypto.h"
+#include "crypto/hash.h"
+#include "ringct/rctSigs.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "cn"
+
+#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d
+
+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,
+ (uint64_t)100, (uint64_t)200, (uint64_t)300, (uint64_t)400, (uint64_t)500, (uint64_t)600, (uint64_t)700, (uint64_t)800, (uint64_t)900,
+ (uint64_t)1000, (uint64_t)2000, (uint64_t)3000, (uint64_t)4000, (uint64_t)5000, (uint64_t)6000, (uint64_t)7000, (uint64_t)8000, (uint64_t)9000,
+ (uint64_t)10000, (uint64_t)20000, (uint64_t)30000, (uint64_t)40000, (uint64_t)50000, (uint64_t)60000, (uint64_t)70000, (uint64_t)80000, (uint64_t)90000,
+ (uint64_t)100000, (uint64_t)200000, (uint64_t)300000, (uint64_t)400000, (uint64_t)500000, (uint64_t)600000, (uint64_t)700000, (uint64_t)800000, (uint64_t)900000,
+ (uint64_t)1000000, (uint64_t)2000000, (uint64_t)3000000, (uint64_t)4000000, (uint64_t)5000000, (uint64_t)6000000, (uint64_t)7000000, (uint64_t)8000000, (uint64_t)9000000, // 1 micronero
+ (uint64_t)10000000, (uint64_t)20000000, (uint64_t)30000000, (uint64_t)40000000, (uint64_t)50000000, (uint64_t)60000000, (uint64_t)70000000, (uint64_t)80000000, (uint64_t)90000000,
+ (uint64_t)100000000, (uint64_t)200000000, (uint64_t)300000000, (uint64_t)400000000, (uint64_t)500000000, (uint64_t)600000000, (uint64_t)700000000, (uint64_t)800000000, (uint64_t)900000000,
+ (uint64_t)1000000000, (uint64_t)2000000000, (uint64_t)3000000000, (uint64_t)4000000000, (uint64_t)5000000000, (uint64_t)6000000000, (uint64_t)7000000000, (uint64_t)8000000000, (uint64_t)9000000000,
+ (uint64_t)10000000000, (uint64_t)20000000000, (uint64_t)30000000000, (uint64_t)40000000000, (uint64_t)50000000000, (uint64_t)60000000000, (uint64_t)70000000000, (uint64_t)80000000000, (uint64_t)90000000000,
+ (uint64_t)100000000000, (uint64_t)200000000000, (uint64_t)300000000000, (uint64_t)400000000000, (uint64_t)500000000000, (uint64_t)600000000000, (uint64_t)700000000000, (uint64_t)800000000000, (uint64_t)900000000000,
+ (uint64_t)1000000000000, (uint64_t)2000000000000, (uint64_t)3000000000000, (uint64_t)4000000000000, (uint64_t)5000000000000, (uint64_t)6000000000000, (uint64_t)7000000000000, (uint64_t)8000000000000, (uint64_t)9000000000000, // 1 monero
+ (uint64_t)10000000000000, (uint64_t)20000000000000, (uint64_t)30000000000000, (uint64_t)40000000000000, (uint64_t)50000000000000, (uint64_t)60000000000000, (uint64_t)70000000000000, (uint64_t)80000000000000, (uint64_t)90000000000000,
+ (uint64_t)100000000000000, (uint64_t)200000000000000, (uint64_t)300000000000000, (uint64_t)400000000000000, (uint64_t)500000000000000, (uint64_t)600000000000000, (uint64_t)700000000000000, (uint64_t)800000000000000, (uint64_t)900000000000000,
+ (uint64_t)1000000000000000, (uint64_t)2000000000000000, (uint64_t)3000000000000000, (uint64_t)4000000000000000, (uint64_t)5000000000000000, (uint64_t)6000000000000000, (uint64_t)7000000000000000, (uint64_t)8000000000000000, (uint64_t)9000000000000000,
+ (uint64_t)10000000000000000, (uint64_t)20000000000000000, (uint64_t)30000000000000000, (uint64_t)40000000000000000, (uint64_t)50000000000000000, (uint64_t)60000000000000000, (uint64_t)70000000000000000, (uint64_t)80000000000000000, (uint64_t)90000000000000000,
+ (uint64_t)100000000000000000, (uint64_t)200000000000000000, (uint64_t)300000000000000000, (uint64_t)400000000000000000, (uint64_t)500000000000000000, (uint64_t)600000000000000000, (uint64_t)700000000000000000, (uint64_t)800000000000000000, (uint64_t)900000000000000000,
+ (uint64_t)1000000000000000000, (uint64_t)2000000000000000000, (uint64_t)3000000000000000000, (uint64_t)4000000000000000000, (uint64_t)5000000000000000000, (uint64_t)6000000000000000000, (uint64_t)7000000000000000000, (uint64_t)8000000000000000000, (uint64_t)9000000000000000000, // 1 meganero
+ (uint64_t)10000000000000000000ull
+};
+
+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);
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx)
+ {
+ crypto::hash h = null_hash;
+ get_transaction_prefix_hash(tx, h);
+ return h;
+ }
+ //---------------------------------------------------------------
+ bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx)
+ {
+ std::stringstream ss;
+ ss << tx_blob;
+ binary_archive<false> ba(ss);
+ bool r = ::serialization::serialize(ba, tx);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash)
+ {
+ std::stringstream ss;
+ ss << tx_blob;
+ binary_archive<false> ba(ss);
+ bool r = ::serialization::serialize(ba, tx);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to parse transaction from blob");
+ //TODO: validate tx
+
+ get_transaction_hash(tx, tx_hash);
+ get_transaction_prefix_hash(tx, tx_prefix_hash);
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki)
+ {
+ crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
+ bool r = crypto::generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
+ CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
+
+ r = crypto::derive_public_key(recv_derivation, real_output_index, ack.m_account_address.m_spend_public_key, in_ephemeral.pub);
+ CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to derive_public_key(" << recv_derivation << ", " << real_output_index << ", " << ack.m_account_address.m_spend_public_key << ")");
+
+ crypto::derive_secret_key(recv_derivation, real_output_index, ack.m_spend_secret_key, in_ephemeral.sec);
+
+ crypto::generate_key_image(in_ephemeral.pub, in_ephemeral.sec, ki);
+ return true;
+ }
+ //---------------------------------------------------------------
+ uint64_t power_integral(uint64_t a, uint64_t b)
+ {
+ if(b == 0)
+ return 1;
+ uint64_t total = a;
+ for(uint64_t i = 1; i != b; i++)
+ total *= a;
+ return total;
+ }
+ //---------------------------------------------------------------
+ bool parse_amount(uint64_t& amount, const std::string& str_amount_)
+ {
+ std::string str_amount = str_amount_;
+ boost::algorithm::trim(str_amount);
+
+ size_t point_index = str_amount.find_first_of('.');
+ size_t fraction_size;
+ if (std::string::npos != point_index)
+ {
+ fraction_size = str_amount.size() - point_index - 1;
+ while (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size && '0' == str_amount.back())
+ {
+ str_amount.erase(str_amount.size() - 1, 1);
+ --fraction_size;
+ }
+ if (CRYPTONOTE_DISPLAY_DECIMAL_POINT < fraction_size)
+ return false;
+ str_amount.erase(point_index, 1);
+ }
+ else
+ {
+ fraction_size = 0;
+ }
+
+ if (str_amount.empty())
+ return false;
+
+ if (fraction_size < CRYPTONOTE_DISPLAY_DECIMAL_POINT)
+ {
+ str_amount.append(CRYPTONOTE_DISPLAY_DECIMAL_POINT - fraction_size, '0');
+ }
+
+ return string_tools::get_xtype_from_string(amount, str_amount);
+ }
+ //---------------------------------------------------------------
+ bool get_tx_fee(const transaction& tx, uint64_t & fee)
+ {
+ if (tx.version > 1)
+ {
+ fee = tx.rct_signatures.txnFee;
+ return true;
+ }
+ uint64_t amount_in = 0;
+ uint64_t amount_out = 0;
+ for(auto& in: tx.vin)
+ {
+ CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), 0, "unexpected type id in transaction");
+ amount_in += boost::get<txin_to_key>(in).amount;
+ }
+ for(auto& o: tx.vout)
+ amount_out += o.amount;
+
+ CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" <<amount_in << ") more than it has (" << amount_out << ")");
+ fee = amount_in - amount_out;
+ return true;
+ }
+ //---------------------------------------------------------------
+ uint64_t get_tx_fee(const transaction& tx)
+ {
+ uint64_t r = 0;
+ if(!get_tx_fee(tx, r))
+ return 0;
+ return r;
+ }
+ //---------------------------------------------------------------
+ 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;
+
+ std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
+ std::istringstream iss(extra_str);
+ binary_archive<false> ar(iss);
+
+ 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 = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+ 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 = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+
+ return true;
+ }
+ //---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const std::vector<uint8_t>& tx_extra, size_t pk_index)
+ {
+ std::vector<tx_extra_field> tx_extra_fields;
+ parse_tx_extra(tx_extra, tx_extra_fields);
+
+ tx_extra_pub_key pub_key_field;
+ if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index))
+ return null_pkey;
+
+ return pub_key_field.pub_key;
+ }
+ //---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const transaction_prefix& tx_prefix, size_t pk_index)
+ {
+ return get_tx_pub_key_from_extra(tx_prefix.extra, pk_index);
+ }
+ //---------------------------------------------------------------
+ crypto::public_key get_tx_pub_key_from_extra(const transaction& tx, size_t pk_index)
+ {
+ return get_tx_pub_key_from_extra(tx.extra, pk_index);
+ }
+ //---------------------------------------------------------------
+ bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key)
+ {
+ tx.extra.resize(tx.extra.size() + 1 + sizeof(crypto::public_key));
+ tx.extra[tx.extra.size() - 1 - sizeof(crypto::public_key)] = TX_EXTRA_TAG_PUBKEY;
+ *reinterpret_cast<crypto::public_key*>(&tx.extra[tx.extra.size() - sizeof(crypto::public_key)]) = tx_pub_key;
+ return true;
+ }
+ //---------------------------------------------------------------
+ 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());
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type)
+ {
+ if (tx_extra.empty())
+ return true;
+ std::string extra_str(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size());
+ std::istringstream iss(extra_str);
+ 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 = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+ if (field.type() != type)
+ ::do_serialize(newar, 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 = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(tx_extra.data()), tx_extra.size())));
+ 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;
+ }
+ //---------------------------------------------------------------
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id)
+ {
+ extra_nonce.clear();
+ extra_nonce.push_back(TX_EXTRA_NONCE_PAYMENT_ID);
+ const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
+ std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
+ }
+ //---------------------------------------------------------------
+ void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id)
+ {
+ extra_nonce.clear();
+ extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID);
+ const uint8_t* payment_id_ptr = reinterpret_cast<const uint8_t*>(&payment_id);
+ std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce));
+ }
+ //---------------------------------------------------------------
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id)
+ {
+ if(sizeof(crypto::hash) + 1 != extra_nonce.size())
+ return false;
+ if(TX_EXTRA_NONCE_PAYMENT_ID != extra_nonce[0])
+ return false;
+ payment_id = *reinterpret_cast<const crypto::hash*>(extra_nonce.data() + 1);
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id)
+ {
+ if(sizeof(crypto::hash8) + 1 != extra_nonce.size())
+ return false;
+ if (TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0])
+ return false;
+ payment_id = *reinterpret_cast<const crypto::hash8*>(extra_nonce.data() + 1);
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key)
+ {
+ crypto::key_derivation derivation;
+ crypto::hash hash;
+ char data[33]; /* A hash, and an extra byte */
+
+ if (!generate_key_derivation(public_key, secret_key, derivation))
+ return false;
+
+ memcpy(data, &derivation, 32);
+ data[32] = ENCRYPTED_PAYMENT_ID_TAIL;
+ cn_fast_hash(data, 33, hash);
+
+ for (size_t b = 0; b < 8; ++b)
+ payment_id.data[b] ^= hash.data[b];
+
+ return true;
+ }
+ bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key)
+ {
+ // Encryption and decryption are the same operation (xor with a key)
+ return encrypt_payment_id(payment_id, public_key, secret_key);
+ }
+ //---------------------------------------------------------------
+ bool get_inputs_money_amount(const transaction& tx, uint64_t& money)
+ {
+ money = 0;
+ for(const auto& in: tx.vin)
+ {
+ CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
+ money += tokey_in.amount;
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
+ uint64_t get_block_height(const block& b)
+ {
+ CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1");
+ CHECKED_GET_SPECIFIC_VARIANT(b.miner_tx.vin[0], const txin_gen, coinbase_in, 0);
+ return coinbase_in.height;
+ }
+ //---------------------------------------------------------------
+ bool check_inputs_types_supported(const transaction& tx)
+ {
+ for(const auto& in: tx.vin)
+ {
+ CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key), false, "wrong variant type: "
+ << in.type().name() << ", expected " << typeid(txin_to_key).name()
+ << ", in transaction id=" << get_transaction_hash(tx));
+
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool check_outs_valid(const transaction& tx)
+ {
+ for(const tx_out& out: tx.vout)
+ {
+ CHECK_AND_ASSERT_MES(out.target.type() == typeid(txout_to_key), false, "wrong variant type: "
+ << out.target.type().name() << ", expected " << typeid(txout_to_key).name()
+ << ", in transaction id=" << get_transaction_hash(tx));
+
+ if (tx.version == 1)
+ {
+ CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx));
+ }
+
+ if(!check_key(boost::get<txout_to_key>(out.target).key))
+ return false;
+ }
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------
+ bool check_money_overflow(const transaction& tx)
+ {
+ return check_inputs_overflow(tx) && check_outs_overflow(tx);
+ }
+ //---------------------------------------------------------------
+ bool check_inputs_overflow(const transaction& tx)
+ {
+ uint64_t money = 0;
+ for(const auto& in: tx.vin)
+ {
+ CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
+ if(money > tokey_in.amount + money)
+ return false;
+ money += tokey_in.amount;
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
+ bool check_outs_overflow(const transaction& tx)
+ {
+ uint64_t money = 0;
+ for(const auto& o: tx.vout)
+ {
+ if(money > o.amount + money)
+ return false;
+ money += o.amount;
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
+ uint64_t get_outs_money_amount(const transaction& tx)
+ {
+ uint64_t outputs_amount = 0;
+ for(const auto& o: tx.vout)
+ outputs_amount += o.amount;
+ return outputs_amount;
+ }
+ //---------------------------------------------------------------
+ std::string short_hash_str(const crypto::hash& h)
+ {
+ std::string res = string_tools::pod_to_hex(h);
+ CHECK_AND_ASSERT_MES(res.size() == 64, res, "wrong hash256 with string_tools::pod_to_hex conversion");
+ auto erased_pos = res.erase(8, 48);
+ res.insert(8, "....");
+ return res;
+ }
+ //---------------------------------------------------------------
+ bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index)
+ {
+ crypto::key_derivation derivation;
+ generate_key_derivation(tx_pub_key, acc.m_view_secret_key, derivation);
+ crypto::public_key pk;
+ derive_public_key(derivation, output_index, acc.m_account_address.m_spend_public_key, pk);
+ return pk == out_key.key;
+ }
+ //---------------------------------------------------------------
+ bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index)
+ {
+ crypto::public_key pk;
+ derive_public_key(derivation, output_index, spend_public_key, pk);
+ return pk == out_key.key;
+ }
+ //---------------------------------------------------------------
+ bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered)
+ {
+ crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx);
+ if(null_pkey == tx_pub_key)
+ return false;
+ return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered);
+ }
+ //---------------------------------------------------------------
+ bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered)
+ {
+ money_transfered = 0;
+ size_t i = 0;
+ for(const tx_out& o: tx.vout)
+ {
+ CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "wrong type id in transaction out" );
+ if(is_out_to_acc(acc, boost::get<txout_to_key>(o.target), tx_pub_key, i))
+ {
+ outs.push_back(i);
+ money_transfered += o.amount;
+ }
+ i++;
+ }
+ return true;
+ }
+ //---------------------------------------------------------------
+ void get_blob_hash(const blobdata& blob, crypto::hash& res)
+ {
+ cn_fast_hash(blob.data(), blob.size(), res);
+ }
+ //---------------------------------------------------------------
+ std::string print_money(uint64_t amount)
+ {
+ std::string s = std::to_string(amount);
+ if(s.size() < CRYPTONOTE_DISPLAY_DECIMAL_POINT+1)
+ {
+ s.insert(0, CRYPTONOTE_DISPLAY_DECIMAL_POINT+1 - s.size(), '0');
+ }
+ s.insert(s.size() - CRYPTONOTE_DISPLAY_DECIMAL_POINT, ".");
+ return s;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_blob_hash(const blobdata& 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;
+ get_transaction_hash(t, h, NULL);
+ return h;
+ }
+ //---------------------------------------------------------------
+ bool get_transaction_hash(const transaction& t, crypto::hash& res)
+ {
+ return get_transaction_hash(t, res, NULL);
+ }
+ //---------------------------------------------------------------
+ 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<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_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<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]);
+ }
+
+ // 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_transaction_hash(t, res, &blob_size);
+ }
+ //---------------------------------------------------------------
+ blobdata get_block_hashing_blob(const block& b)
+ {
+ blobdata blob = t_serializable_object_to_blob(static_cast<block_header>(b));
+ crypto::hash tree_root_hash = get_tx_tree_hash(b);
+ blob.append(reinterpret_cast<const char*>(&tree_root_hash), sizeof(tree_root_hash));
+ blob.append(tools::get_varint_data(b.tx_hashes.size()+1));
+ return blob;
+ }
+ //---------------------------------------------------------------
+ bool get_block_hash(const block& b, crypto::hash& res)
+ {
+ // EXCEPTION FOR BLOCK 202612
+ const std::string correct_blob_hash_202612 = "3a8a2b3a29b50fc86ff73dd087ea43c6f0d6b8f936c849194d5c84c737903966";
+ const std::string existing_block_id_202612 = "bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698";
+ crypto::hash block_blob_hash = get_blob_hash(block_to_blob(b));
+
+ if (string_tools::pod_to_hex(block_blob_hash) == correct_blob_hash_202612)
+ {
+ string_tools::hex_to_pod(existing_block_id_202612, res);
+ return true;
+ }
+ bool hash_result = get_object_hash(get_block_hashing_blob(b), res);
+
+ if (hash_result)
+ {
+ // make sure that we aren't looking at a block with the 202612 block id but not the correct blobdata
+ if (string_tools::pod_to_hex(res) == existing_block_id_202612)
+ {
+ LOG_ERROR("Block with block id for 202612 but incorrect block blob hash found!");
+ res = null_hash;
+ return false;
+ }
+ }
+ return hash_result;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_block_hash(const block& b)
+ {
+ crypto::hash p = null_hash;
+ get_block_hash(b, p);
+ return p;
+ }
+ //---------------------------------------------------------------
+ bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height)
+ {
+ // block 202612 bug workaround
+ const std::string longhash_202612 = "84f64766475d51837ac9efbef1926486e58563c95a19fef4aec3254f03000000";
+ if (height == 202612)
+ {
+ string_tools::hex_to_pod(longhash_202612, res);
+ return true;
+ }
+ block b_local = b; //workaround to avoid const errors with do_serialize
+ blobdata bd = get_block_hashing_blob(b);
+ crypto::cn_slow_hash(bd.data(), bd.size(), res);
+ return true;
+ }
+ //---------------------------------------------------------------
+ std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off)
+ {
+ std::vector<uint64_t> res = off;
+ for(size_t i = 1; i < res.size(); i++)
+ res[i] += res[i-1];
+ return res;
+ }
+ //---------------------------------------------------------------
+ std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off)
+ {
+ std::vector<uint64_t> res = off;
+ if(!off.size())
+ return res;
+ std::sort(res.begin(), res.end());//just to be sure, actually it is already should be sorted
+ for(size_t i = res.size()-1; i != 0; i--)
+ res[i] -= res[i-1];
+
+ return res;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_block_longhash(const block& b, uint64_t height)
+ {
+ crypto::hash p = null_hash;
+ get_block_longhash(b, p, height);
+ return p;
+ }
+ //---------------------------------------------------------------
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b)
+ {
+ 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");
+ return true;
+ }
+ //---------------------------------------------------------------
+ blobdata block_to_blob(const block& b)
+ {
+ return t_serializable_object_to_blob(b);
+ }
+ //---------------------------------------------------------------
+ bool block_to_blob(const block& b, blobdata& b_blob)
+ {
+ return t_serializable_object_to_blob(b, b_blob);
+ }
+ //---------------------------------------------------------------
+ blobdata tx_to_blob(const transaction& tx)
+ {
+ return t_serializable_object_to_blob(tx);
+ }
+ //---------------------------------------------------------------
+ bool tx_to_blob(const transaction& tx, blobdata& b_blob)
+ {
+ return t_serializable_object_to_blob(tx, b_blob);
+ }
+ //---------------------------------------------------------------
+ void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h)
+ {
+ tree_hash(tx_hashes.data(), tx_hashes.size(), h);
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes)
+ {
+ crypto::hash h = null_hash;
+ get_tx_tree_hash(tx_hashes, h);
+ return h;
+ }
+ //---------------------------------------------------------------
+ crypto::hash get_tx_tree_hash(const block& b)
+ {
+ std::vector<crypto::hash> txs_ids;
+ crypto::hash h = null_hash;
+ size_t bl_sz = 0;
+ get_transaction_hash(b.miner_tx, h, bl_sz);
+ txs_ids.push_back(h);
+ for(auto& th: b.tx_hashes)
+ txs_ids.push_back(th);
+ return get_tx_tree_hash(txs_ids);
+ }
+ //---------------------------------------------------------------
+ bool is_valid_decomposed_amount(uint64_t amount)
+ {
+ const uint64_t *begin = valid_decomposed_outputs;
+ const uint64_t *end = valid_decomposed_outputs + sizeof(valid_decomposed_outputs) / sizeof(valid_decomposed_outputs[0]);
+ return std::binary_search(begin, end, amount);
+ }
+ //---------------------------------------------------------------
+}
diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h
new file mode 100644
index 000000000..3ac456bb8
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_format_utils.h
@@ -0,0 +1,213 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+#include "cryptonote_protocol/cryptonote_protocol_defs.h"
+#include "cryptonote_basic_impl.h"
+#include "account.h"
+#include "include_base_utils.h"
+#include "crypto/crypto.h"
+#include "crypto/hash.h"
+#include "ringct/rctOps.h"
+
+namespace cryptonote
+{
+ //---------------------------------------------------------------
+ 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_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);
+ bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key);
+ bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key);
+
+ 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)
+ {
+ auto it = std::find_if(tx_extra_fields.begin(), tx_extra_fields.end(), [&index](const tx_extra_field& f) { return typeid(T) == f.type() && !index--; });
+ if(tx_extra_fields.end() == it)
+ return false;
+
+ field = boost::get<T>(*it);
+ return true;
+ }
+
+ bool parse_tx_extra(const std::vector<uint8_t>& tx_extra, std::vector<tx_extra_field>& tx_extra_fields);
+ 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);
+ bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key);
+ bool add_extra_nonce_to_tx_extra(std::vector<uint8_t>& tx_extra, const blobdata& extra_nonce);
+ bool remove_field_from_tx_extra(std::vector<uint8_t>& tx_extra, const std::type_info &type);
+ void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id);
+ void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id);
+ bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id);
+ bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id);
+ bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index);
+ bool is_out_to_acc_precomp(const crypto::public_key& spend_public_key, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
+ bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<size_t>& outs, uint64_t& money_transfered);
+ bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered);
+ bool get_tx_fee(const transaction& tx, uint64_t & fee);
+ uint64_t get_tx_fee(const transaction& tx);
+ bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki);
+ void get_blob_hash(const blobdata& blob, crypto::hash& res);
+ crypto::hash get_blob_hash(const blobdata& 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);
+ blobdata get_block_hashing_blob(const block& b);
+ 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);
+ crypto::hash get_block_longhash(const block& b, uint64_t height);
+ bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
+ 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);
+ bool check_outs_valid(const transaction& tx);
+ bool parse_amount(uint64_t& amount, const std::string& str_amount);
+
+ bool check_money_overflow(const transaction& tx);
+ bool check_outs_overflow(const transaction& tx);
+ bool check_inputs_overflow(const transaction& tx);
+ uint64_t get_block_height(const block& b);
+ std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off);
+ std::vector<uint64_t> absolute_output_offsets_to_relative(const std::vector<uint64_t>& off);
+ std::string print_money(uint64_t amount);
+ //---------------------------------------------------------------
+ template<class t_object>
+ bool t_serializable_object_to_blob(const t_object& to, blobdata& b_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;
+ }
+ //---------------------------------------------------------------
+ template<class t_object>
+ blobdata t_serializable_object_to_blob(const t_object& to)
+ {
+ blobdata b;
+ t_serializable_object_to_blob(to, b);
+ return b;
+ }
+ //---------------------------------------------------------------
+ template<class t_object>
+ bool get_object_hash(const t_object& 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)
+ {
+ blobdata b = t_serializable_object_to_blob(o);
+ return b.size();
+ }
+ //---------------------------------------------------------------
+ template<class t_object>
+ bool get_object_hash(const t_object& o, crypto::hash& res, size_t& blob_size)
+ {
+ blobdata bl = t_serializable_object_to_blob(o);
+ blob_size = bl.size();
+ get_blob_hash(bl, res);
+ return true;
+ }
+ //---------------------------------------------------------------
+ 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");
+ return ss.str();
+ }
+ //---------------------------------------------------------------
+ // 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold
+ template<typename chunk_handler_t, typename dust_handler_t>
+ void decompose_amount_into_digits(uint64_t amount, uint64_t dust_threshold, const chunk_handler_t& chunk_handler, const dust_handler_t& dust_handler)
+ {
+ if (0 == amount)
+ {
+ return;
+ }
+
+ bool is_dust_handled = false;
+ uint64_t dust = 0;
+ uint64_t order = 1;
+ while (0 != amount)
+ {
+ uint64_t chunk = (amount % 10) * order;
+ amount /= 10;
+ order *= 10;
+
+ if (dust + chunk <= dust_threshold)
+ {
+ dust += chunk;
+ }
+ else
+ {
+ if (!is_dust_handled && 0 != dust)
+ {
+ dust_handler(dust);
+ is_dust_handled = true;
+ }
+ if (0 != chunk)
+ {
+ chunk_handler(chunk);
+ }
+ }
+ }
+
+ if (!is_dust_handled && 0 != dust)
+ {
+ dust_handler(dust);
+ }
+ }
+ //---------------------------------------------------------------
+ blobdata block_to_blob(const block& b);
+ bool block_to_blob(const block& b, blobdata& b_blob);
+ blobdata tx_to_blob(const transaction& b);
+ bool tx_to_blob(const transaction& b, blobdata& b_blob);
+ void get_tx_tree_hash(const std::vector<crypto::hash>& tx_hashes, crypto::hash& h);
+ 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);
+
+#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()); \
+ specific_type& variable_name = boost::get<specific_type>(variant_var);
+
+}
diff --git a/src/cryptonote_basic/cryptonote_stat_info.h b/src/cryptonote_basic/cryptonote_stat_info.h
new file mode 100644
index 000000000..d44904b6d
--- /dev/null
+++ b/src/cryptonote_basic/cryptonote_stat_info.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+#include "serialization/keyvalue_serialization.h"
+
+
+namespace cryptonote
+{
+ struct core_stat_info
+ {
+ uint64_t tx_pool_size;
+ uint64_t blockchain_height;
+ uint64_t mining_speed;
+ uint64_t alternative_blocks;
+ std::string top_block_id_str;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(tx_pool_size)
+ KV_SERIALIZE(blockchain_height)
+ KV_SERIALIZE(mining_speed)
+ KV_SERIALIZE(alternative_blocks)
+ KV_SERIALIZE(top_block_id_str)
+ END_KV_SERIALIZE_MAP()
+ };
+}
diff --git a/src/cryptonote_basic/difficulty.cpp b/src/cryptonote_basic/difficulty.cpp
new file mode 100644
index 000000000..1c5b9cfbd
--- /dev/null
+++ b/src/cryptonote_basic/difficulty.cpp
@@ -0,0 +1,165 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+#include "common/int-util.h"
+#include "crypto/hash.h"
+#include "cryptonote_config.h"
+#include "difficulty.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "difficulty"
+
+namespace cryptonote {
+
+ using std::size_t;
+ using std::uint64_t;
+ using std::vector;
+
+#if defined(__x86_64__)
+ static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
+ low = mul128(a, b, &high);
+ }
+
+#else
+
+ static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
+ // __int128 isn't part of the standard, so the previous function wasn't portable. mul128() in Windows is fine,
+ // but this portable function should be used elsewhere. Credit for this function goes to latexi95.
+
+ uint64_t aLow = a & 0xFFFFFFFF;
+ uint64_t aHigh = a >> 32;
+ uint64_t bLow = b & 0xFFFFFFFF;
+ uint64_t bHigh = b >> 32;
+
+ uint64_t res = aLow * bLow;
+ uint64_t lowRes1 = res & 0xFFFFFFFF;
+ uint64_t carry = res >> 32;
+
+ res = aHigh * bLow + carry;
+ uint64_t highResHigh1 = res >> 32;
+ uint64_t highResLow1 = res & 0xFFFFFFFF;
+
+ res = aLow * bHigh;
+ uint64_t lowRes2 = res & 0xFFFFFFFF;
+ carry = res >> 32;
+
+ res = aHigh * bHigh + carry;
+ uint64_t highResHigh2 = res >> 32;
+ uint64_t highResLow2 = res & 0xFFFFFFFF;
+
+ //Addition
+
+ uint64_t r = highResLow1 + lowRes2;
+ carry = r >> 32;
+ low = (r << 32) | lowRes1;
+ r = highResHigh1 + highResLow2 + carry;
+ uint64_t d3 = r & 0xFFFFFFFF;
+ carry = r >> 32;
+ r = highResHigh2 + carry;
+ high = d3 | (r << 32);
+ }
+
+#endif
+
+ static inline bool cadd(uint64_t a, uint64_t b) {
+ return a + b < a;
+ }
+
+ static inline bool cadc(uint64_t a, uint64_t b, bool c) {
+ return a + b < a || (c && a + b == (uint64_t) -1);
+ }
+
+ bool check_hash(const crypto::hash &hash, difficulty_type difficulty) {
+ uint64_t low, high, top, cur;
+ // First check the highest word, this will most likely fail for a random hash.
+ mul(swap64le(((const uint64_t *) &hash)[3]), difficulty, top, high);
+ if (high != 0) {
+ return false;
+ }
+ mul(swap64le(((const uint64_t *) &hash)[0]), difficulty, low, cur);
+ mul(swap64le(((const uint64_t *) &hash)[1]), difficulty, low, high);
+ bool carry = cadd(cur, low);
+ cur = high;
+ mul(swap64le(((const uint64_t *) &hash)[2]), difficulty, low, high);
+ carry = cadc(cur, low, carry);
+ carry = cadc(high, top, carry);
+ return !carry;
+ }
+
+ difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds) {
+
+ if(timestamps.size() > DIFFICULTY_WINDOW)
+ {
+ timestamps.resize(DIFFICULTY_WINDOW);
+ cumulative_difficulties.resize(DIFFICULTY_WINDOW);
+ }
+
+
+ size_t length = timestamps.size();
+ assert(length == cumulative_difficulties.size());
+ if (length <= 1) {
+ return 1;
+ }
+ static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
+ assert(length <= DIFFICULTY_WINDOW);
+ sort(timestamps.begin(), timestamps.end());
+ size_t cut_begin, cut_end;
+ static_assert(2 * DIFFICULTY_CUT <= DIFFICULTY_WINDOW - 2, "Cut length is too large");
+ if (length <= DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) {
+ cut_begin = 0;
+ cut_end = length;
+ } else {
+ cut_begin = (length - (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT) + 1) / 2;
+ cut_end = cut_begin + (DIFFICULTY_WINDOW - 2 * DIFFICULTY_CUT);
+ }
+ assert(/*cut_begin >= 0 &&*/ cut_begin + 2 <= cut_end && cut_end <= length);
+ uint64_t time_span = timestamps[cut_end - 1] - timestamps[cut_begin];
+ if (time_span == 0) {
+ time_span = 1;
+ }
+ difficulty_type total_work = cumulative_difficulties[cut_end - 1] - cumulative_difficulties[cut_begin];
+ assert(total_work > 0);
+ uint64_t low, high;
+ mul(total_work, target_seconds, low, high);
+ // blockchain errors "difficulty overhead" if this function returns zero.
+ // TODO: consider throwing an exception instead
+ if (high != 0 || low + time_span - 1 < low) {
+ return 0;
+ }
+ return (low + time_span - 1) / time_span;
+ }
+
+}
diff --git a/src/cryptonote_basic/difficulty.h b/src/cryptonote_basic/difficulty.h
new file mode 100644
index 000000000..910f97035
--- /dev/null
+++ b/src/cryptonote_basic/difficulty.h
@@ -0,0 +1,56 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+#include "crypto/hash.h"
+
+namespace cryptonote
+{
+ typedef std::uint64_t difficulty_type;
+
+ /**
+ * @brief checks if a hash fits the given difficulty
+ *
+ * The hash passes if (hash * difficulty) < 2^192.
+ * Phrased differently, if (hash * difficulty) fits without overflow into
+ * the least significant 192 bits of the 256 bit multiplication result.
+ *
+ * @param hash the hash to check
+ * @param difficulty the difficulty to check against
+ *
+ * @return true if valid, else false
+ */
+ bool check_hash(const crypto::hash &hash, difficulty_type difficulty);
+ difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
+}
diff --git a/src/cryptonote_basic/hardfork.cpp b/src/cryptonote_basic/hardfork.cpp
new file mode 100644
index 000000000..9b2434970
--- /dev/null
+++ b/src/cryptonote_basic/hardfork.cpp
@@ -0,0 +1,416 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <algorithm>
+#include <cstdio>
+
+#include "cryptonote_basic.h"
+#include "blockchain_db/blockchain_db.h"
+#include "hardfork.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "hardfork"
+
+using namespace cryptonote;
+
+static uint8_t get_block_vote(const cryptonote::block &b)
+{
+ // Pre-hardfork blocks have a minor version hardcoded to 0.
+ // For the purposes of voting, we consider 0 to refer to
+ // version number 1, which is what all blocks from the genesis
+ // block are. It makes things simpler.
+ if (b.minor_version == 0)
+ return 1;
+ return b.minor_version;
+}
+
+static uint8_t get_block_version(const cryptonote::block &b)
+{
+ return b.major_version;
+}
+
+HardFork::HardFork(cryptonote::BlockchainDB &db, uint8_t original_version, uint64_t original_version_till_height, time_t forked_time, time_t update_time, uint64_t window_size, uint8_t default_threshold_percent):
+ db(db),
+ original_version(original_version),
+ original_version_till_height(original_version_till_height),
+ forked_time(forked_time),
+ update_time(update_time),
+ window_size(window_size),
+ default_threshold_percent(default_threshold_percent)
+{
+ if (window_size == 0)
+ throw "window_size needs to be strictly positive";
+ if (default_threshold_percent > 100)
+ throw "default_threshold_percent needs to be between 0 and 100";
+}
+
+bool HardFork::add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time)
+{
+ CRITICAL_REGION_LOCAL(lock);
+
+ // add in order
+ if (version == 0)
+ return false;
+ if (!heights.empty()) {
+ if (version <= heights.back().version)
+ return false;
+ if (height <= heights.back().height)
+ return false;
+ if (time <= heights.back().time)
+ return false;
+ }
+ if (threshold > 100)
+ return false;
+ heights.push_back(Params(version, height, threshold, time));
+ return true;
+}
+
+bool HardFork::add_fork(uint8_t version, uint64_t height, time_t time)
+{
+ return add_fork(version, height, default_threshold_percent, time);
+}
+
+uint8_t HardFork::get_effective_version(uint8_t voting_version) const
+{
+ if (!heights.empty()) {
+ uint8_t max_version = heights.back().version;
+ if (voting_version > max_version)
+ voting_version = max_version;
+ }
+ return voting_version;
+}
+
+bool HardFork::do_check(uint8_t block_version, uint8_t voting_version) const
+{
+ return block_version == heights[current_fork_index].version
+ && voting_version >= heights[current_fork_index].version;
+}
+
+bool HardFork::check(const cryptonote::block &block) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ return do_check(::get_block_version(block), ::get_block_vote(block));
+}
+
+bool HardFork::do_check_for_height(uint8_t block_version, uint8_t voting_version, uint64_t height) const
+{
+ int fork_index = get_voted_fork_index(height);
+ return block_version == heights[fork_index].version
+ && voting_version >= heights[fork_index].version;
+}
+
+bool HardFork::check_for_height(const cryptonote::block &block, uint64_t height) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ return do_check_for_height(::get_block_version(block), ::get_block_vote(block), height);
+}
+
+bool HardFork::add(uint8_t block_version, uint8_t voting_version, uint64_t height)
+{
+ CRITICAL_REGION_LOCAL(lock);
+
+ if (!do_check(block_version, voting_version))
+ return false;
+
+ db.set_hard_fork_version(height, heights[current_fork_index].version);
+
+ voting_version = get_effective_version(voting_version);
+
+ while (versions.size() >= window_size) {
+ const uint8_t old_version = versions.front();
+ assert(last_versions[old_version] >= 1);
+ last_versions[old_version]--;
+ versions.pop_front();
+ }
+
+ last_versions[voting_version]++;
+ versions.push_back(voting_version);
+
+ uint8_t voted = get_voted_fork_index(height + 1);
+ if (voted > current_fork_index) {
+ current_fork_index = voted;
+ }
+
+ return true;
+}
+
+bool HardFork::add(const cryptonote::block &block, uint64_t height)
+{
+ return add(::get_block_version(block), ::get_block_vote(block), height);
+}
+
+void HardFork::init()
+{
+ CRITICAL_REGION_LOCAL(lock);
+
+ // add a placeholder for the default version, to avoid special cases
+ if (heights.empty())
+ heights.push_back(Params(original_version, 0, 0, 0));
+
+ versions.clear();
+ for (size_t n = 0; n < 256; ++n)
+ last_versions[n] = 0;
+ current_fork_index = 0;
+
+ // restore state from DB
+ uint64_t height = db.height();
+ if (height > window_size)
+ height -= window_size - 1;
+ else
+ height = 1;
+
+ bool populate = false;
+ try
+ {
+ db.get_hard_fork_version(0);
+ }
+ catch (...) { populate = true; }
+ if (populate) {
+ LOG_PRINT_L0("The DB has no hard fork info, reparsing from start");
+ height = 1;
+ }
+ LOG_PRINT_L1("reorganizing from " << height);
+ if (populate) {
+ reorganize_from_chain_height(height);
+ // reorg will not touch the genesis block, use this as a flag for populating done
+ db.set_hard_fork_version(0, original_version);
+ }
+ else {
+ rescan_from_chain_height(height);
+ }
+ LOG_PRINT_L1("reorganization done");
+}
+
+uint8_t HardFork::get_block_version(uint64_t height) const
+{
+ if (height <= original_version_till_height)
+ return original_version;
+
+ const cryptonote::block &block = db.get_block_from_height(height);
+ return ::get_block_version(block);
+}
+
+bool HardFork::reorganize_from_block_height(uint64_t height)
+{
+ CRITICAL_REGION_LOCAL(lock);
+ if (height >= db.height())
+ return false;
+
+ db.set_batch_transactions(true);
+ db.batch_start();
+
+ versions.clear();
+
+ for (size_t n = 0; n < 256; ++n)
+ last_versions[n] = 0;
+ const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0;
+ const uint8_t start_version = height == 0 ? original_version : db.get_hard_fork_version(height);
+ while (current_fork_index > 0 && heights[current_fork_index].version > start_version) {
+ --current_fork_index;
+ }
+ for (uint64_t h = rescan_height; h <= height; ++h) {
+ cryptonote::block b = db.get_block_from_height(h);
+ const uint8_t v = get_effective_version(get_block_vote(b));
+ last_versions[v]++;
+ versions.push_back(v);
+ }
+
+ uint8_t voted = get_voted_fork_index(height + 1);
+ if (voted > current_fork_index) {
+ current_fork_index = voted;
+ }
+
+ const uint64_t bc_height = db.height();
+ for (uint64_t h = height + 1; h < bc_height; ++h) {
+ add(db.get_block_from_height(h), h);
+ }
+
+ db.batch_stop();
+
+ return true;
+}
+
+bool HardFork::reorganize_from_chain_height(uint64_t height)
+{
+ if (height == 0)
+ return false;
+ return reorganize_from_block_height(height - 1);
+}
+
+bool HardFork::rescan_from_block_height(uint64_t height)
+{
+ CRITICAL_REGION_LOCAL(lock);
+ db.block_txn_start(true);
+ if (height >= db.height()) {
+ db.block_txn_stop();
+ return false;
+ }
+
+ versions.clear();
+
+ for (size_t n = 0; n < 256; ++n)
+ last_versions[n] = 0;
+ for (uint64_t h = height; h < db.height(); ++h) {
+ cryptonote::block b = db.get_block_from_height(h);
+ const uint8_t v = get_effective_version(get_block_vote(b));
+ last_versions[v]++;
+ versions.push_back(v);
+ }
+
+ uint8_t lastv = db.get_hard_fork_version(db.height() - 1);
+ current_fork_index = 0;
+ while (current_fork_index + 1 < heights.size() && heights[current_fork_index].version != lastv)
+ ++current_fork_index;
+
+ uint8_t voted = get_voted_fork_index(db.height());
+ if (voted > current_fork_index) {
+ current_fork_index = voted;
+ }
+
+ db.block_txn_stop();
+
+ return true;
+}
+
+bool HardFork::rescan_from_chain_height(uint64_t height)
+{
+ if (height == 0)
+ return false;
+ return rescan_from_block_height(height - 1);
+}
+
+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) {
+ uint8_t v = heights[n].version;
+ accumulated_votes += last_versions[v];
+ uint32_t threshold = (window_size * heights[n].threshold + 99) / 100;
+ if (height >= heights[n].height && accumulated_votes >= threshold) {
+ return n;
+ }
+ }
+ return current_fork_index;
+}
+
+HardFork::State HardFork::get_state(time_t t) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+
+ // no hard forks setup yet
+ if (heights.size() <= 1)
+ return Ready;
+
+ time_t t_last_fork = heights.back().time;
+ if (t >= t_last_fork + forked_time)
+ return LikelyForked;
+ if (t >= t_last_fork + update_time)
+ return UpdateNeeded;
+ return Ready;
+}
+
+HardFork::State HardFork::get_state() const
+{
+ return get_state(time(NULL));
+}
+
+uint8_t HardFork::get(uint64_t height) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ if (height > db.height()) {
+ assert(false);
+ return 255;
+ }
+ if (height == db.height()) {
+ return get_current_version();
+ }
+ return db.get_hard_fork_version(height);
+}
+
+uint8_t HardFork::get_current_version() const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ return heights[current_fork_index].version;
+}
+
+uint8_t HardFork::get_ideal_version() const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ return heights.back().version;
+}
+
+uint8_t HardFork::get_ideal_version(uint64_t height) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+ for (unsigned int n = heights.size() - 1; n > 0; --n) {
+ if (height >= heights[n].height) {
+ return heights[n].version;
+ }
+ }
+ return original_version;
+}
+
+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;
+ }
+ return 0;
+}
+
+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;
+ }
+ }
+ return original_version;
+}
+
+bool HardFork::get_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const
+{
+ CRITICAL_REGION_LOCAL(lock);
+
+ const uint8_t current_version = heights[current_fork_index].version;
+ const bool enabled = current_version >= version;
+ window = versions.size();
+ votes = 0;
+ for (size_t n = version; n < 256; ++n)
+ votes += last_versions[n];
+ threshold = (window * heights[current_fork_index].threshold + 99) / 100;
+ //assert((votes >= threshold) == enabled);
+ earliest_height = get_earliest_ideal_height_for_version(version);
+ voting = heights.back().version;
+ return enabled;
+}
+
diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h
new file mode 100644
index 000000000..a8ab32af7
--- /dev/null
+++ b/src/cryptonote_basic/hardfork.h
@@ -0,0 +1,265 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#pragma once
+
+#include "syncobj.h"
+#include "cryptonote_basic.h"
+
+namespace cryptonote
+{
+ class BlockchainDB;
+
+ class HardFork
+ {
+ public:
+ typedef enum {
+ LikelyForked,
+ UpdateNeeded,
+ Ready,
+ } State;
+
+ static const uint64_t DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT = 0; // <= actual height
+ static const time_t DEFAULT_FORKED_TIME = 31557600; // a year in seconds
+ static const time_t DEFAULT_UPDATE_TIME = 31557600 / 2;
+ static const uint64_t DEFAULT_WINDOW_SIZE = 10080; // supermajority window check length - a week
+ static const uint8_t DEFAULT_THRESHOLD_PERCENT = 80;
+
+ /**
+ * @brief creates a new HardFork object
+ *
+ * @param original_version the block version for blocks 0 through to the first fork
+ * @param forked_time the time in seconds before thinking we're forked
+ * @param update_time the time in seconds before thinking we need to update
+ * @param window_size the size of the window in blocks to consider for version voting
+ * @param default_threshold_percent the size of the majority in percents
+ */
+ HardFork(cryptonote::BlockchainDB &db, uint8_t original_version = 1, uint64_t original_version_till_height = DEFAULT_ORIGINAL_VERSION_TILL_HEIGHT, time_t forked_time = DEFAULT_FORKED_TIME, time_t update_time = DEFAULT_UPDATE_TIME, uint64_t window_size = DEFAULT_WINDOW_SIZE, uint8_t default_threshold_percent = DEFAULT_THRESHOLD_PERCENT);
+
+ /**
+ * @brief add a new hardfork height
+ *
+ * returns true if no error, false otherwise
+ *
+ * @param version the major block version for the fork
+ * @param height The height the hardfork takes effect
+ * @param threshold The threshold of votes needed for this fork (0-100)
+ * @param time Approximate time of the hardfork (seconds since epoch)
+ */
+ bool add_fork(uint8_t version, uint64_t height, uint8_t threshold, time_t time);
+
+ /**
+ * @brief add a new hardfork height
+ *
+ * returns true if no error, false otherwise
+ *
+ * @param version the major block version for the fork
+ * @param voting_version the minor block version for the fork, used for voting
+ * @param height The height the hardfork takes effect
+ * @param time Approximate time of the hardfork (seconds since epoch)
+ */
+ bool add_fork(uint8_t version, uint64_t height, time_t time);
+
+ /**
+ * @brief initialize the object
+ *
+ * Must be done after adding all the required hardforks via add above
+ */
+ void init();
+
+ /**
+ * @brief check whether a new block would be accepted
+ *
+ * returns true if the block is accepted, false otherwise
+ *
+ * @param block the new block
+ *
+ * This check is made by add. It is exposed publicly to allow
+ * the caller to inexpensively check whether a block would be
+ * accepted or rejected by its version number. Indeed, if this
+ * check could only be done as part of add, the caller would
+ * either have to add the block to the blockchain first, then
+ * call add, then have to pop the block from the blockchain if
+ * its version did not satisfy the hard fork requirements, or
+ * call add first, then, if the hard fork requirements are met,
+ * add the block to the blockchain, upon which a failure (the
+ * block being invalid, double spending, etc) would cause the
+ * hardfork object to reorganize.
+ */
+ bool check(const cryptonote::block &block) const;
+
+ /**
+ * @brief same as check, but for a particular height, rather than the top
+ *
+ * NOTE: this does not play well with voting, and relies on voting to be
+ * disabled (that is, forks happen on the scheduled date, whether or not
+ * enough blocks have voted for the fork).
+ *
+ * returns true if no error, false otherwise
+ *
+ * @param block the new block
+ * @param height which height to check for
+ */
+ bool check_for_height(const cryptonote::block &block, uint64_t height) const;
+
+ /**
+ * @brief add a new block
+ *
+ * returns true if no error, false otherwise
+ *
+ * @param block the new block
+ */
+ bool add(const cryptonote::block &block, uint64_t height);
+
+ /**
+ * @brief called when the blockchain is reorganized
+ *
+ * This will rescan the blockchain to determine which hard forks
+ * have been triggered
+ *
+ * returns true if no error, false otherwise
+ *
+ * @param blockchain the blockchain
+ * @param height of the last block kept from the previous blockchain
+ */
+ bool reorganize_from_block_height(uint64_t height);
+ bool reorganize_from_chain_height(uint64_t height);
+
+ /**
+ * @brief returns current state at the given time
+ *
+ * Based on the approximate time of the last known hard fork,
+ * estimate whether we need to update, or if we're way behind
+ *
+ * @param t the time to consider
+ */
+ State get_state(time_t t) const;
+ State get_state() const;
+
+ /**
+ * @brief returns the hard fork version for the given block height
+ *
+ * @param height height of the block to check
+ */
+ uint8_t get(uint64_t height) const;
+
+ /**
+ * @brief returns the latest "ideal" version
+ *
+ * This is the latest version that's been scheduled
+ */
+ uint8_t get_ideal_version() const;
+
+ /**
+ * @brief returns the "ideal" version for a given height
+ *
+ * @param height height of the block to check
+ */
+ uint8_t get_ideal_version(uint64_t height) const;
+
+ /**
+ * @brief returns the next version
+ *
+ * This is the version which will we fork to next
+ */
+ uint8_t get_next_version() const;
+
+ /**
+ * @brief returns the current version
+ *
+ * This is the latest version that's past its trigger date and had enough votes
+ * at one point in the past.
+ */
+ uint8_t get_current_version() const;
+
+ /**
+ * @brief returns the earliest block a given version may activate
+ */
+ uint64_t get_earliest_ideal_height_for_version(uint8_t version) const;
+
+ /**
+ * @brief returns information about current voting state
+ *
+ * returns true if the given version is enabled (ie, the current version
+ * is at least the passed version), false otherwise
+ *
+ * @param version the version to check voting for
+ * @param window the number of blocks considered in voting
+ * @param votes number of votes for next version
+ * @param threshold number of votes needed to switch to next version
+ * @param earliest_height earliest height at which the version can take effect
+ */
+ bool get_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const;
+
+ /**
+ * @brief returns the size of the voting window in blocks
+ */
+ uint64_t get_window_size() const { return window_size; }
+
+ private:
+
+ uint8_t get_block_version(uint64_t height) const;
+ bool do_check(uint8_t block_version, uint8_t voting_version) const;
+ bool do_check_for_height(uint8_t block_version, uint8_t voting_version, uint64_t height) const;
+ int get_voted_fork_index(uint64_t height) const;
+ uint8_t get_effective_version(uint8_t voting_version) const;
+ bool add(uint8_t block_version, uint8_t voting_version, uint64_t height);
+
+ bool rescan_from_block_height(uint64_t height);
+ bool rescan_from_chain_height(uint64_t height);
+
+ private:
+
+ BlockchainDB &db;
+
+ time_t forked_time;
+ time_t update_time;
+ uint64_t window_size;
+ uint8_t default_threshold_percent;
+
+ uint8_t original_version;
+ uint64_t original_version_till_height;
+
+ struct Params {
+ uint8_t version;
+ uint8_t threshold;
+ uint64_t height;
+ time_t time;
+ Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {}
+ };
+ std::vector<Params> heights;
+
+ std::deque<uint8_t> versions; /* rolling window of the last N blocks' versions */
+ unsigned int last_versions[256]; /* count of the block versions in the last N blocks */
+ uint32_t current_fork_index;
+
+ mutable epee::critical_section lock;
+ };
+
+} // namespace cryptonote
+
diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp
new file mode 100644
index 000000000..88c631f80
--- /dev/null
+++ b/src/cryptonote_basic/miner.cpp
@@ -0,0 +1,414 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#include <sstream>
+#include <numeric>
+#include <boost/utility/value_init.hpp>
+#include <boost/interprocess/detail/atomic.hpp>
+#include <boost/limits.hpp>
+#include "misc_language.h"
+#include "include_base_utils.h"
+#include "cryptonote_basic_impl.h"
+#include "cryptonote_format_utils.h"
+#include "file_io_utils.h"
+#include "common/command_line.h"
+#include "string_coding.h"
+#include "storages/portable_storage_template_helper.h"
+
+#undef MONERO_DEFAULT_LOG_CATEGORY
+#define MONERO_DEFAULT_LOG_CATEGORY "miner"
+
+using namespace epee;
+
+#include "miner.h"
+
+
+extern "C" void slow_hash_allocate_state();
+extern "C" void slow_hash_free_state();
+namespace cryptonote
+{
+
+ namespace
+ {
+ const command_line::arg_descriptor<std::string> arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
+ const command_line::arg_descriptor<std::string> arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true};
+ const command_line::arg_descriptor<uint32_t> arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true};
+ }
+
+
+ miner::miner(i_miner_handler* phandler):m_stop(1),
+ m_template(boost::value_initialized<block>()),
+ m_template_no(0),
+ m_diffic(0),
+ m_thread_index(0),
+ m_phandler(phandler),
+ m_height(0),
+ m_pausers_count(0),
+ m_threads_total(0),
+ m_starter_nonce(0),
+ m_last_hr_merge_time(0),
+ m_hashes(0),
+ m_do_print_hashrate(false),
+ m_do_mining(false),
+ m_current_hash_rate(0)
+ {
+
+ }
+ //-----------------------------------------------------------------------------------------------------
+ miner::~miner()
+ {
+ stop();
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::set_block_template(const block& bl, const difficulty_type& di, uint64_t height)
+ {
+ CRITICAL_REGION_LOCAL(m_template_lock);
+ m_template = bl;
+ m_diffic = di;
+ m_height = height;
+ ++m_template_no;
+ m_starter_nonce = crypto::rand<uint32_t>();
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::on_block_chain_update()
+ {
+ if(!is_mining())
+ return true;
+
+ return request_block_template();
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::request_block_template()
+ {
+ block bl = AUTO_VAL_INIT(bl);
+ difficulty_type di = AUTO_VAL_INIT(di);
+ uint64_t height = AUTO_VAL_INIT(height);
+ cryptonote::blobdata extra_nonce;
+ if(m_extra_messages.size() && m_config.current_extra_message_index < m_extra_messages.size())
+ {
+ extra_nonce = m_extra_messages[m_config.current_extra_message_index];
+ }
+
+ if(!m_phandler->get_block_template(bl, m_mine_address, di, height, extra_nonce))
+ {
+ LOG_ERROR("Failed to get_block_template(), stopping mining");
+ return false;
+ }
+ set_block_template(bl, di, height);
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::on_idle()
+ {
+ m_update_block_template_interval.do_call([&](){
+ if(is_mining())request_block_template();
+ return true;
+ });
+
+ m_update_merge_hr_interval.do_call([&](){
+ merge_hr();
+ return true;
+ });
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::do_print_hashrate(bool do_hr)
+ {
+ m_do_print_hashrate = do_hr;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::merge_hr()
+ {
+ if(m_last_hr_merge_time && is_mining())
+ {
+ m_current_hash_rate = m_hashes * 1000 / ((misc_utils::get_tick_count() - m_last_hr_merge_time + 1));
+ CRITICAL_REGION_LOCAL(m_last_hash_rates_lock);
+ m_last_hash_rates.push_back(m_current_hash_rate);
+ if(m_last_hash_rates.size() > 19)
+ m_last_hash_rates.pop_front();
+ if(m_do_print_hashrate)
+ {
+ uint64_t total_hr = std::accumulate(m_last_hash_rates.begin(), m_last_hash_rates.end(), 0);
+ float hr = static_cast<float>(total_hr)/static_cast<float>(m_last_hash_rates.size());
+ std::cout << "hashrate: " << std::setprecision(4) << std::fixed << hr << ENDL;
+ }
+ }
+ m_last_hr_merge_time = misc_utils::get_tick_count();
+ m_hashes = 0;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::init_options(boost::program_options::options_description& desc)
+ {
+ command_line::add_arg(desc, arg_extra_messages);
+ command_line::add_arg(desc, arg_start_mining);
+ command_line::add_arg(desc, arg_mining_threads);
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::init(const boost::program_options::variables_map& vm, bool testnet)
+ {
+ if(command_line::has_arg(vm, arg_extra_messages))
+ {
+ std::string buff;
+ bool r = file_io_utils::load_file_to_string(command_line::get_arg(vm, arg_extra_messages), buff);
+ CHECK_AND_ASSERT_MES(r, false, "Failed to load file with extra messages: " << command_line::get_arg(vm, arg_extra_messages));
+ std::vector<std::string> extra_vec;
+ boost::split(extra_vec, buff, boost::is_any_of("\n"), boost::token_compress_on );
+ m_extra_messages.resize(extra_vec.size());
+ for(size_t i = 0; i != extra_vec.size(); i++)
+ {
+ string_tools::trim(extra_vec[i]);
+ if(!extra_vec[i].size())
+ continue;
+ std::string buff = string_encoding::base64_decode(extra_vec[i]);
+ if(buff != "0")
+ m_extra_messages[i] = buff;
+ }
+ 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);
+ MINFO("Loaded " << m_extra_messages.size() << " extra messages, current index " << m_config.current_extra_message_index);
+ }
+
+ if(command_line::has_arg(vm, arg_start_mining))
+ {
+ if(!cryptonote::get_account_address_from_str(m_mine_address, testnet, command_line::get_arg(vm, arg_start_mining)))
+ {
+ LOG_ERROR("Target account address " << command_line::get_arg(vm, arg_start_mining) << " has wrong format, starting daemon canceled");
+ return false;
+ }
+ m_threads_total = 1;
+ m_do_mining = true;
+ if(command_line::has_arg(vm, arg_mining_threads))
+ {
+ m_threads_total = command_line::get_arg(vm, arg_mining_threads);
+ }
+ }
+
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::is_mining() const
+ {
+ return !m_stop;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ const account_public_address& miner::get_mining_address() const
+ {
+ return m_mine_address;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint32_t miner::get_threads_count() const {
+ return m_threads_total;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs)
+ {
+ m_mine_address = adr;
+ m_threads_total = static_cast<uint32_t>(threads_count);
+ m_starter_nonce = crypto::rand<uint32_t>();
+ CRITICAL_REGION_LOCAL(m_threads_lock);
+ if(is_mining())
+ {
+ LOG_ERROR("Starting miner but it's already started");
+ return false;
+ }
+
+ if(!m_threads.empty())
+ {
+ LOG_ERROR("Unable to start miner because there are active mining threads");
+ return false;
+ }
+
+ if(!m_template_no)
+ request_block_template();//lets update block template
+
+ boost::interprocess::ipcdetail::atomic_write32(&m_stop, 0);
+ boost::interprocess::ipcdetail::atomic_write32(&m_thread_index, 0);
+
+ for(size_t i = 0; i != threads_count; 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!" );
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ uint64_t miner::get_speed() const
+ {
+ if(is_mining()) {
+ return m_current_hash_rate;
+ }
+ else {
+ return 0;
+ }
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::send_stop_signal()
+ {
+ boost::interprocess::ipcdetail::atomic_write32(&m_stop, 1);
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::stop()
+ {
+ MTRACE("Miner has received stop signal");
+
+ if (!is_mining())
+ {
+ MDEBUG("Not mining - nothing to stop" );
+ return true;
+ }
+
+ send_stop_signal();
+ CRITICAL_REGION_LOCAL(m_threads_lock);
+
+ for(boost::thread& th: m_threads)
+ th.join();
+
+ MINFO("Mining has been stopped, " << m_threads.size() << " finished" );
+ m_threads.clear();
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height)
+ {
+ for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
+ {
+ crypto::hash h;
+ get_block_longhash(bl, h, height);
+
+ if(check_hash(h, diffic))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::on_synchronized()
+ {
+ if(m_do_mining)
+ {
+ boost::thread::attributes attrs;
+ attrs.set_stack_size(THREAD_STACK_SIZE);
+
+ start(m_mine_address, m_threads_total, attrs);
+ }
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::pause()
+ {
+ CRITICAL_REGION_LOCAL(m_miners_count_lock);
+ ++m_pausers_count;
+ if(m_pausers_count == 1 && is_mining())
+ MDEBUG("MINING PAUSED");
+ }
+ //-----------------------------------------------------------------------------------------------------
+ void miner::resume()
+ {
+ CRITICAL_REGION_LOCAL(m_miners_count_lock);
+ --m_pausers_count;
+ if(m_pausers_count < 0)
+ {
+ m_pausers_count = 0;
+ MERROR("Unexpected miner::resume() called");
+ }
+ if(!m_pausers_count && is_mining())
+ MDEBUG("MINING RESUMED");
+ }
+ //-----------------------------------------------------------------------------------------------------
+ bool miner::worker_thread()
+ {
+ uint32_t th_local_index = boost::interprocess::ipcdetail::atomic_inc32(&m_thread_index);
+ MGINFO("Miner thread was started ["<< th_local_index << "]");
+ MLOG_SET_THREAD_NAME(std::string("[miner ") + std::to_string(th_local_index) + "]");
+ uint32_t nonce = m_starter_nonce + th_local_index;
+ uint64_t height = 0;
+ difficulty_type local_diff = 0;
+ uint32_t local_template_ver = 0;
+ block b;
+ slow_hash_allocate_state();
+ while(!m_stop)
+ {
+ if(m_pausers_count)//anti split workaround
+ {
+ misc_utils::sleep_no_w(100);
+ continue;
+ }
+
+ if(local_template_ver != m_template_no)
+ {
+ CRITICAL_REGION_BEGIN(m_template_lock);
+ b = m_template;
+ local_diff = m_diffic;
+ height = m_height;
+ CRITICAL_REGION_END();
+ local_template_ver = m_template_no;
+ nonce = m_starter_nonce + th_local_index;
+ }
+
+ if(!local_template_ver)//no any set_block_template call
+ {
+ LOG_PRINT_L2("Block template not set yet");
+ epee::misc_utils::sleep_no_w(1000);
+ continue;
+ }
+
+ b.nonce = nonce;
+ crypto::hash h;
+ get_block_longhash(b, h, height);
+
+ if(check_hash(h, local_diff))
+ {
+ //we lucky!
+ ++m_config.current_extra_message_index;
+ MGINFO_GREEN("Found block for difficulty: " << local_diff);
+ if(!m_phandler->handle_block_found(b))
+ {
+ --m_config.current_extra_message_index;
+ }else
+ {
+ //success update, lets update config
+ if (!m_config_folder_path.empty())
+ epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME);
+ }
+ }
+ nonce+=m_threads_total;
+ ++m_hashes;
+ }
+ slow_hash_free_state();
+ MGINFO("Miner thread stopped ["<< th_local_index << "]");
+ return true;
+ }
+ //-----------------------------------------------------------------------------------------------------
+}
+
diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h
new file mode 100644
index 000000000..f24f6e960
--- /dev/null
+++ b/src/cryptonote_basic/miner.h
@@ -0,0 +1,126 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+#include <boost/program_options.hpp>
+#include <atomic>
+#include "cryptonote_basic.h"
+#include "difficulty.h"
+#include "math_helper.h"
+
+
+namespace cryptonote
+{
+
+ struct i_miner_handler
+ {
+ virtual bool handle_block_found(block& b) = 0;
+ virtual bool get_block_template(block& b, const account_public_address& adr, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) = 0;
+ protected:
+ ~i_miner_handler(){};
+ };
+
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ class miner
+ {
+ public:
+ miner(i_miner_handler* phandler);
+ ~miner();
+ bool init(const boost::program_options::variables_map& vm, bool testnet);
+ 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 on_block_chain_update();
+ bool start(const account_public_address& adr, size_t threads_count, const boost::thread::attributes& attrs);
+ uint64_t get_speed() const;
+ uint32_t get_threads_count() const;
+ void send_stop_signal();
+ bool stop();
+ bool is_mining() const;
+ const account_public_address& get_mining_address() const;
+ bool on_idle();
+ void on_synchronized();
+ //synchronous analog (for fast calls)
+ static bool find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height);
+ void pause();
+ void resume();
+ void do_print_hashrate(bool do_hr);
+
+ private:
+ bool worker_thread();
+ bool request_block_template();
+ void merge_hr();
+
+ struct miner_config
+ {
+ uint64_t current_extra_message_index;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(current_extra_message_index)
+ END_KV_SERIALIZE_MAP()
+ };
+
+
+ volatile uint32_t m_stop;
+ epee::critical_section m_template_lock;
+ block m_template;
+ std::atomic<uint32_t> m_template_no;
+ std::atomic<uint32_t> m_starter_nonce;
+ difficulty_type m_diffic;
+ uint64_t m_height;
+ volatile uint32_t m_thread_index;
+ volatile uint32_t m_threads_total;
+ std::atomic<int32_t> m_pausers_count;
+ epee::critical_section m_miners_count_lock;
+
+ std::list<boost::thread> m_threads;
+ epee::critical_section m_threads_lock;
+ i_miner_handler* m_phandler;
+ 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;
+ 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_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;
+
+ };
+}
+
+
+
diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h
new file mode 100644
index 000000000..6f5fbe466
--- /dev/null
+++ b/src/cryptonote_basic/tx_extra.h
@@ -0,0 +1,182 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+
+
+#define TX_EXTRA_PADDING_MAX_COUNT 255
+#define TX_EXTRA_NONCE_MAX_COUNT 255
+
+#define TX_EXTRA_TAG_PADDING 0x00
+#define TX_EXTRA_TAG_PUBKEY 0x01
+#define TX_EXTRA_NONCE 0x02
+#define TX_EXTRA_MERGE_MINING_TAG 0x03
+#define TX_EXTRA_MYSTERIOUS_MINERGATE_TAG 0xDE
+
+#define TX_EXTRA_NONCE_PAYMENT_ID 0x00
+#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01
+
+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;
+ }
+ };
+
+ struct tx_extra_pub_key
+ {
+ crypto::public_key pub_key;
+
+ BEGIN_SERIALIZE()
+ FIELD(pub_key)
+ END_SERIALIZE()
+ };
+
+ struct tx_extra_nonce
+ {
+ std::string nonce;
+
+ BEGIN_SERIALIZE()
+ FIELD(nonce)
+ if(TX_EXTRA_NONCE_MAX_COUNT < nonce.size()) return false;
+ 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);
+ }
+ };
+
+ struct tx_extra_mysterious_minergate
+ {
+ std::string data;
+
+ BEGIN_SERIALIZE()
+ FIELD(data)
+ END_SERIALIZE()
+ };
+
+ // tx_extra_field format, except tx_extra_padding and tx_extra_pub_key:
+ // 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_mysterious_minergate> tx_extra_field;
+}
+
+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_mysterious_minergate, TX_EXTRA_MYSTERIOUS_MINERGATE_TAG);
diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h
new file mode 100644
index 000000000..0bb635e84
--- /dev/null
+++ b/src/cryptonote_basic/verification_context.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2014-2016, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+
+#pragma once
+namespace cryptonote
+{
+ /************************************************************************/
+ /* */
+ /************************************************************************/
+ struct tx_verification_context
+ {
+ bool m_should_be_relayed;
+ bool m_verifivation_failed; //bad tx, should drop connection
+ bool m_verifivation_impossible; //the transaction is related with an alternative blockchain
+ bool m_added_to_pool;
+ bool m_low_mixin;
+ bool m_double_spend;
+ bool m_invalid_input;
+ bool m_invalid_output;
+ bool m_too_big;
+ bool m_overspend;
+ bool m_fee_too_low;
+ bool m_not_rct;
+ };
+
+ struct block_verification_context
+ {
+ bool m_added_to_main_chain;
+ bool m_verifivation_failed; //bad block, should drop connection
+ bool m_marked_as_orphaned;
+ bool m_already_exists;
+ bool m_partial_block_reward;
+ };
+}