Merge pull request #203 from wowario/wow

♪♪ It’s a moment when I show up, got'em sayin WOW ♫♪♪
pull/205/head
jw 5 years ago committed by GitHub
commit 007032c83b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

3
.gitmodules vendored

@ -12,3 +12,6 @@
[submodule "external/trezor-common"] [submodule "external/trezor-common"]
path = external/trezor-common path = external/trezor-common
url = https://github.com/trezor/trezor-common.git url = https://github.com/trezor/trezor-common.git
[submodule "external/randomwow"]
path = external/randomwow
url = https://github.com/wownero/RandomWOW

@ -205,6 +205,7 @@ if(NOT MANUAL_SUBMODULES)
check_submodule(external/unbound) check_submodule(external/unbound)
check_submodule(external/rapidjson) check_submodule(external/rapidjson)
check_submodule(external/trezor-common) check_submodule(external/trezor-common)
check_submodule(external/randomwow)
endif() endif()
endif() endif()

@ -40,7 +40,7 @@ Dates are provided in the format YYYY-MM-DD.
| 53666 | 2018-10-06 | Cool Cage | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS | 53666 | 2018-10-06 | Cool Cage | v0.3.0.0 | v0.3.1.3 | Cryptonight variant 2, LWMA v2, ringsize = 22, MMS
| 63469 | 2018-11-11 | Dank Doge | v0.4.0.0 | v0.4.0.0 | LWMA v4 | 63469 | 2018-11-11 | Dank Doge | v0.4.0.0 | v0.4.0.0 | LWMA v4
| 81769 | 2019-02-19 | Erotic EggplantEmoji | v0.5.0.0 | v0.5.0.2 | Cryptonight/wow, LWMA v1 with N=144, Updated Bulletproofs, Fee Per Byte, Auto-churn | 81769 | 2019-02-19 | Erotic EggplantEmoji | v0.5.0.0 | v0.5.0.2 | Cryptonight/wow, LWMA v1 with N=144, Updated Bulletproofs, Fee Per Byte, Auto-churn
| XXXXX | 2019-XX-XX | F For Fappening | v0.6.0.0 | v0.6.0.0 | New PoW based on RandomX, new block weight algorithm, slightly more efficient RingCT format | 114969 | 2019-06-14 | F For Fappening | v0.6.0.0 | v0.6.0.0 | RandomWOW, new block weight algorithm, slightly more efficient RingCT format
X's indicate that these details have not been determined as of commit date. X's indicate that these details have not been determined as of commit date.

@ -100,3 +100,4 @@ endif()
add_subdirectory(db_drivers) add_subdirectory(db_drivers)
add_subdirectory(easylogging++) add_subdirectory(easylogging++)
add_subdirectory(randomwow)

@ -0,0 +1 @@
Subproject commit 435a8382d88cf81a85af680ff00dde7644ad4478

@ -129,6 +129,15 @@ struct tx_data_t
}; };
#pragma pack(pop) #pragma pack(pop)
struct alt_block_data_t
{
uint64_t height;
uint64_t cumulative_weight;
uint64_t cumulative_difficulty_low;
uint64_t cumulative_difficulty_high;
uint64_t already_generated_coins;
};
/** /**
* @brief a struct containing txpool per transaction metadata * @brief a struct containing txpool per transaction metadata
*/ */
@ -1543,8 +1552,45 @@ public:
* *
* @param: sz the block size * @param: sz the block size
*/ */
virtual void add_max_block_size(uint64_t sz) = 0; virtual void add_max_block_size(uint64_t sz) = 0;
/**
* @brief add a new alternative block
*
* @param: blkid the block hash
* @param: data: the metadata for the block
* @param: blob: the block's blob
*/
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) = 0;
/**
* @brief get an alternative block by hash
*
* @param: blkid the block hash
* @param: data: the metadata for the block
* @param: blob: the block's blob
*
* @return true if the block was found in the alternative blocks list, false otherwise
*/
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) = 0;
/**
* @brief remove an alternative block
*
* @param: blkid the block hash
*/
virtual void remove_alt_block(const crypto::hash &blkid) = 0;
/**
* @brief get the number of alternative blocks stored
*/
virtual uint64_t get_alt_block_count() = 0;
/**
* @brief drop all alternative blocks
*/
virtual void drop_alt_blocks() = 0;
/** /**
* @brief runs a function over all txpool transactions * @brief runs a function over all txpool transactions
* *
@ -1634,6 +1680,23 @@ public:
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const = 0; virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const = 0;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const = 0; virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const = 0;
/**
* @brief runs a function over all alternative blocks stored
*
* The subclass should run the passed function for each alt block it has
* stored, passing (blkid, data, blob) as its parameters.
*
* If any call to the function returns false, the subclass should return
* false. Otherwise, the subclass returns true.
*
* The subclass should throw DB_ERROR if any of the expected values are
* not found. Current implementations simply return false.
*
* @param std::function f the function to run
*
* @return false if the function returns false for any output, otherwise true
*/
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const = 0;
// //

@ -194,6 +194,8 @@ namespace
* txpool_meta txn hash txn metadata * txpool_meta txn hash txn metadata
* txpool_blob txn hash txn blob * txpool_blob txn hash txn blob
* *
* alt_blocks block hash {block data, block blob}
*
* Note: where the data items are of uniform size, DUPFIXED tables have * Note: where the data items are of uniform size, DUPFIXED tables have
* been used to save space. In most of these cases, a dummy "zerokval" * been used to save space. In most of these cases, a dummy "zerokval"
* key is used when accessing the table; the Key listed above will be * key is used when accessing the table; the Key listed above will be
@ -221,6 +223,8 @@ const char* const LMDB_SPENT_KEYS = "spent_keys";
const char* const LMDB_TXPOOL_META = "txpool_meta"; const char* const LMDB_TXPOOL_META = "txpool_meta";
const char* const LMDB_TXPOOL_BLOB = "txpool_blob"; const char* const LMDB_TXPOOL_BLOB = "txpool_blob";
const char* const LMDB_ALT_BLOCKS = "alt_blocks";
const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights"; const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights";
const char* const LMDB_HF_VERSIONS = "hf_versions"; const char* const LMDB_HF_VERSIONS = "hf_versions";
@ -1400,6 +1404,8 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
lmdb_db_open(txn, LMDB_TXPOOL_META, MDB_CREATE, m_txpool_meta, "Failed to open db handle for m_txpool_meta"); lmdb_db_open(txn, LMDB_TXPOOL_META, MDB_CREATE, m_txpool_meta, "Failed to open db handle for m_txpool_meta");
lmdb_db_open(txn, LMDB_TXPOOL_BLOB, MDB_CREATE, m_txpool_blob, "Failed to open db handle for m_txpool_blob"); lmdb_db_open(txn, LMDB_TXPOOL_BLOB, MDB_CREATE, m_txpool_blob, "Failed to open db handle for m_txpool_blob");
lmdb_db_open(txn, LMDB_ALT_BLOCKS, MDB_CREATE, m_alt_blocks, "Failed to open db handle for m_alt_blocks");
// this subdb is dropped on sight, so it may not be present when we open the DB. // this subdb is dropped on sight, so it may not be present when we open the DB.
// Since we use MDB_CREATE, we'll get an exception if we open read-only and it does not exist. // Since we use MDB_CREATE, we'll get an exception if we open read-only and it does not exist.
// So we don't open for read-only, and also not drop below. It is not used elsewhere. // So we don't open for read-only, and also not drop below. It is not used elsewhere.
@ -1423,6 +1429,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags)
mdb_set_compare(txn, m_txpool_meta, compare_hash32); mdb_set_compare(txn, m_txpool_meta, compare_hash32);
mdb_set_compare(txn, m_txpool_blob, compare_hash32); mdb_set_compare(txn, m_txpool_blob, compare_hash32);
mdb_set_compare(txn, m_alt_blocks, compare_hash32);
mdb_set_compare(txn, m_properties, compare_string); mdb_set_compare(txn, m_properties, compare_string);
if (!(mdb_flags & MDB_RDONLY)) if (!(mdb_flags & MDB_RDONLY))
@ -2241,6 +2248,50 @@ bool BlockchainLMDB::for_all_txpool_txes(std::function<bool(const crypto::hash&,
return ret; return ret;
} }
bool BlockchainLMDB::for_all_alt_blocks(std::function<bool(const crypto::hash&, const alt_block_data_t&, const cryptonote::blobdata*)> f, bool include_blob) const
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(alt_blocks);
MDB_val k;
MDB_val v;
bool ret = true;
MDB_cursor_op op = MDB_FIRST;
while (1)
{
int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, op);
op = MDB_NEXT;
if (result == MDB_NOTFOUND)
break;
if (result)
throw0(DB_ERROR(lmdb_error("Failed to enumerate alt blocks: ", result).c_str()));
const crypto::hash &blkid = *(const crypto::hash*)k.mv_data;
if (v.mv_size < sizeof(alt_block_data_t))
throw0(DB_ERROR("alt_blocks record is too small"));
const alt_block_data_t *data = (const alt_block_data_t*)v.mv_data;
const cryptonote::blobdata *passed_bd = NULL;
cryptonote::blobdata bd;
if (include_blob)
{
bd.assign(reinterpret_cast<const char*>(v.mv_data) + sizeof(alt_block_data_t), v.mv_size - sizeof(alt_block_data_t));
passed_bd = &bd;
}
if (!f(blkid, *data, passed_bd)) {
ret = false;
break;
}
}
TXN_POSTFIX_RDONLY();
return ret;
}
bool BlockchainLMDB::block_exists(const crypto::hash& h, uint64_t *height) const bool BlockchainLMDB::block_exists(const crypto::hash& h, uint64_t *height) const
{ {
LOG_PRINT_L3("BlockchainLMDB::" << __func__); LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@ -4062,6 +4113,110 @@ uint8_t BlockchainLMDB::get_hard_fork_version(uint64_t height) const
return ret; return ret;
} }
void BlockchainLMDB::add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(alt_blocks)
MDB_val k = {sizeof(blkid), (void *)&blkid};
const size_t val_size = sizeof(alt_block_data_t) + blob.size();
std::unique_ptr<char[]> val(new char[val_size]);
memcpy(val.get(), &data, sizeof(alt_block_data_t));
memcpy(val.get() + sizeof(alt_block_data_t), blob.data(), blob.size());
MDB_val v = {val_size, (void *)val.get()};
if (auto result = mdb_cursor_put(m_cur_alt_blocks, &k, &v, MDB_NODUPDATA)) {
if (result == MDB_KEYEXIST)
throw1(DB_ERROR("Attempting to add alternate block that's already in the db"));
else
throw1(DB_ERROR(lmdb_error("Error adding alternate block to db transaction: ", result).c_str()));
}
}
bool BlockchainLMDB::get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob)
{
LOG_PRINT_L3("BlockchainLMDB:: " << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(alt_blocks);
MDB_val_set(k, blkid);
MDB_val v;
int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET);
if (result == MDB_NOTFOUND)
return false;
if (result)
throw0(DB_ERROR(lmdb_error("Error attempting to retrieve alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str()));
if (v.mv_size < sizeof(alt_block_data_t))
throw0(DB_ERROR("Record size is less than expected"));
const alt_block_data_t *ptr = (const alt_block_data_t*)v.mv_data;
if (data)
*data = *ptr;
if (blob)
blob->assign((const char*)(ptr + 1), v.mv_size - sizeof(alt_block_data_t));
TXN_POSTFIX_RDONLY();
return true;
}
void BlockchainLMDB::remove_alt_block(const crypto::hash &blkid)
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
mdb_txn_cursors *m_cursors = &m_wcursors;
CURSOR(alt_blocks)
MDB_val k = {sizeof(blkid), (void *)&blkid};
MDB_val v;
int result = mdb_cursor_get(m_cur_alt_blocks, &k, &v, MDB_SET);
if (result)
throw0(DB_ERROR(lmdb_error("Error locating alternate block " + epee::string_tools::pod_to_hex(blkid) + " in the db: ", result).c_str()));
result = mdb_cursor_del(m_cur_alt_blocks, 0);
if (result)
throw0(DB_ERROR(lmdb_error("Error deleting alternate block " + epee::string_tools::pod_to_hex(blkid) + " from the db: ", result).c_str()));
}
uint64_t BlockchainLMDB::get_alt_block_count()
{
LOG_PRINT_L3("BlockchainLMDB:: " << __func__);
check_open();
TXN_PREFIX_RDONLY();
RCURSOR(alt_blocks);
MDB_stat db_stats;
int result = mdb_stat(m_txn, m_alt_blocks, &db_stats);
uint64_t count = 0;
if (result != MDB_NOTFOUND)
{
if (result)
throw0(DB_ERROR(lmdb_error("Failed to query m_alt_blocks: ", result).c_str()));
count = db_stats.ms_entries;
}
TXN_POSTFIX_RDONLY();
return count;
}
void BlockchainLMDB::drop_alt_blocks()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
check_open();
TXN_PREFIX(0);
auto result = mdb_drop(*txn_ptr, m_alt_blocks, 0);
if (result)
throw1(DB_ERROR(lmdb_error("Error dropping alternative blocks: ", result).c_str()));
TXN_POSTFIX_SUCCESS();
}
bool BlockchainLMDB::is_read_only() const bool BlockchainLMDB::is_read_only() const
{ {
unsigned int flags; unsigned int flags;

@ -67,6 +67,8 @@ typedef struct mdb_txn_cursors
MDB_cursor *m_txc_txpool_meta; MDB_cursor *m_txc_txpool_meta;
MDB_cursor *m_txc_txpool_blob; MDB_cursor *m_txc_txpool_blob;
MDB_cursor *m_txc_alt_blocks;
MDB_cursor *m_txc_hf_versions; MDB_cursor *m_txc_hf_versions;
MDB_cursor *m_txc_properties; MDB_cursor *m_txc_properties;
@ -87,6 +89,7 @@ typedef struct mdb_txn_cursors
#define m_cur_spent_keys m_cursors->m_txc_spent_keys #define m_cur_spent_keys m_cursors->m_txc_spent_keys
#define m_cur_txpool_meta m_cursors->m_txc_txpool_meta #define m_cur_txpool_meta m_cursors->m_txc_txpool_meta
#define m_cur_txpool_blob m_cursors->m_txc_txpool_blob #define m_cur_txpool_blob m_cursors->m_txc_txpool_blob
#define m_cur_alt_blocks m_cursors->m_txc_alt_blocks
#define m_cur_hf_versions m_cursors->m_txc_hf_versions #define m_cur_hf_versions m_cursors->m_txc_hf_versions
#define m_cur_properties m_cursors->m_txc_properties #define m_cur_properties m_cursors->m_txc_properties
@ -108,6 +111,7 @@ typedef struct mdb_rflags
bool m_rf_spent_keys; bool m_rf_spent_keys;
bool m_rf_txpool_meta; bool m_rf_txpool_meta;
bool m_rf_txpool_blob; bool m_rf_txpool_blob;
bool m_rf_alt_blocks;
bool m_rf_hf_versions; bool m_rf_hf_versions;
bool m_rf_properties; bool m_rf_properties;
} mdb_rflags; } mdb_rflags;
@ -288,6 +292,12 @@ public:
virtual bool update_pruning(); virtual bool update_pruning();
virtual bool check_pruning(); virtual bool check_pruning();
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob);
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob);
virtual void remove_alt_block(const crypto::hash &blkid);
virtual uint64_t get_alt_block_count();
virtual void drop_alt_blocks();
virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const; virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)> f, bool include_blob = false, bool include_unrelayed_txes = true) const;
virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const; virtual bool for_all_key_images(std::function<bool(const crypto::key_image&)>) const;
@ -295,6 +305,7 @@ public:
virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const; virtual bool for_all_transactions(std::function<bool(const crypto::hash&, const cryptonote::transaction&)>, bool pruned) const;
virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const; virtual bool for_all_outputs(std::function<bool(uint64_t amount, const crypto::hash &tx_hash, uint64_t height, size_t tx_idx)> f) const;
virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const; virtual bool for_all_outputs(uint64_t amount, const std::function<bool(uint64_t height)> &f) const;
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const;
virtual uint64_t add_block( const std::pair<block, blobdata>& blk virtual uint64_t add_block( const std::pair<block, blobdata>& blk
, size_t block_weight , size_t block_weight
@ -452,6 +463,8 @@ private:
MDB_dbi m_txpool_meta; MDB_dbi m_txpool_meta;
MDB_dbi m_txpool_blob; MDB_dbi m_txpool_blob;
MDB_dbi m_alt_blocks;
MDB_dbi m_hf_starting_heights; MDB_dbi m_hf_starting_heights;
MDB_dbi m_hf_versions; MDB_dbi m_hf_versions;

@ -156,6 +156,13 @@ public:
virtual uint64_t get_max_block_size() override { return 100000000; } virtual uint64_t get_max_block_size() override { return 100000000; }
virtual void add_max_block_size(uint64_t sz) override { } virtual void add_max_block_size(uint64_t sz) override { }
virtual void add_alt_block(const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata &blob) override {}
virtual bool get_alt_block(const crypto::hash &blkid, alt_block_data_t *data, cryptonote::blobdata *blob) override { return false; }
virtual void remove_alt_block(const crypto::hash &blkid) override {}
virtual uint64_t get_alt_block_count() override { return 0; }
virtual void drop_alt_blocks() override {}
virtual bool for_all_alt_blocks(std::function<bool(const crypto::hash &blkid, const alt_block_data_t &data, const cryptonote::blobdata *blob)> f, bool include_blob = false) const override { return true; }
}; };
} }

@ -46,6 +46,7 @@ set(crypto_sources
random.c random.c
skein.c skein.c
slow-hash.c slow-hash.c
rx-slow-hash.c
CryptonightR_JIT.c CryptonightR_JIT.c
tree-hash.c) tree-hash.c)
@ -53,6 +54,8 @@ if(ARCH_ID STREQUAL "i386" OR ARCH_ID STREQUAL "x86_64" OR ARCH_ID STREQUAL "x86
list(APPEND crypto_sources CryptonightR_template.S) list(APPEND crypto_sources CryptonightR_template.S)
endif() endif()
include_directories(${RANDOMX_INCLUDE})
set(crypto_headers) set(crypto_headers)
set(crypto_private_headers set(crypto_private_headers
@ -86,6 +89,7 @@ monero_add_library(cncrypto
target_link_libraries(cncrypto target_link_libraries(cncrypto
PUBLIC PUBLIC
epee epee
randomx
${Boost_SYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY}
${SODIUM_LIBRARY} ${SODIUM_LIBRARY}
PRIVATE PRIVATE

@ -0,0 +1,56 @@
// Copyright (c) 2019, 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.
/* Brain-dead simple portability wrapper over thread APIs for C */
#pragma once
#ifdef _WIN32
#include <windows.h>
#define CTHR_MUTEX_TYPE HANDLE
#define CTHR_MUTEX_INIT NULL
#define CTHR_MUTEX_LOCK(x) do { if (x == NULL) { \
HANDLE p = CreateMutex(NULL, FALSE, NULL); \
if (InterlockedCompareExchangePointer((PVOID*)&x, (PVOID)p, NULL) != NULL) \
CloseHandle(p); \
} WaitForSingleObject(x, INFINITE) == WAIT_FAILED; } while(0)
#define CTHR_MUTEX_UNLOCK(x) (ReleaseMutex(x) == 0)
#define CTHR_THREAD_TYPE HANDLE
#define CTHR_THREAD_RTYPE void
#define CTHR_THREAD_CREATE(thr, func, arg) thr = _beginthread(func, 0, arg)
#define CTHR_THREAD_JOIN(thr) WaitForSingleObject(thr, INFINITE)
#else
#include <pthread.h>
#define CTHR_MUTEX_TYPE pthread_mutex_t
#define CTHR_MUTEX_INIT PTHREAD_MUTEX_INITIALIZER
#define CTHR_MUTEX_LOCK(x) pthread_mutex_lock(&x)
#define CTHR_MUTEX_UNLOCK(x) pthread_mutex_unlock(&x)
#define CTHR_THREAD_TYPE pthread_t
#define CTHR_THREAD_RTYPE void *
#define CTHR_THREAD_CREATE(thr, func, arg) pthread_create(&thr, NULL, func, arg)
#define CTHR_THREAD_JOIN(thr) pthread_join(thr, NULL)
#endif

@ -87,3 +87,14 @@ void hash_extra_jh(const void *data, size_t length, char *hash);
void hash_extra_skein(const void *data, size_t length, char *hash); void hash_extra_skein(const void *data, size_t length, char *hash);
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash); void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash);
#define RX_BLOCK_VERSION 12
void rx_slow_hash_allocate_state(void);
void rx_slow_hash_free_state(void);
uint64_t rx_seedheight(const uint64_t height);
void rx_seedheights(const uint64_t height, uint64_t *seed_height, uint64_t *next_height);
bool rx_needhash(const uint64_t height, uint64_t *seedheight);
void rx_seedhash(const uint64_t seedheight, const char *hash, const int miners);
void rx_slow_hash(const void *data, size_t length, char *hash, const int miners);
void rx_alt_slowhash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, char *hash);
void rx_reorg(const uint64_t split_height);

@ -0,0 +1,349 @@
// Copyright (c) 2019, 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 <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "randomx.h"
#include "c_threads.h"
#include "hash-ops.h"
#if defined(_MSC_VER)
#define THREADV __declspec(thread)
#else
#define THREADV __thread
#endif
static CTHR_MUTEX_TYPE rx_mutex = CTHR_MUTEX_INIT;
typedef struct rx_state {
volatile uint64_t rs_height;
randomx_cache *rs_cache;
} rx_state;
static rx_state rx_s[2];
static randomx_dataset *rx_dataset;
THREADV int rx_s_toggle;
THREADV randomx_vm *rx_vm = NULL;
static void local_abort(const char *msg)
{
fprintf(stderr, "%s\n", msg);
#ifdef NDEBUG
_exit(1);
#else
abort();
#endif
}
/**
* @brief uses cpuid to determine if the CPU supports the AES instructions
* @return true if the CPU supports AES, false otherwise
*/
static inline int force_software_aes(void)
{
static int use = -1;
if (use != -1)
return use;
const char *env = getenv("MONERO_USE_SOFTWARE_AES");
if (!env) {
use = 0;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use = 0;
}
else {
use = 1;
}
return use;
}
static void cpuid(int CPUInfo[4], int InfoType)
{
#if defined(__x86_64__)
__asm __volatile__
(
"cpuid":
"=a" (CPUInfo[0]),
"=b" (CPUInfo[1]),
"=c" (CPUInfo[2]),
"=d" (CPUInfo[3]) :
"a" (InfoType), "c" (0)
);
#endif
}
static inline int check_aes_hw(void)
{
#if defined(__x86_64__)
int cpuid_results[4];
static int supported = -1;
if(supported >= 0)
return supported;
cpuid(cpuid_results,1);
return supported = cpuid_results[2] & (1 << 25);
#else
return 0;
#endif
}
static volatile int use_rx_jit_flag = -1;
static inline int use_rx_jit(void)
{
#if defined(__x86_64__)
if (use_rx_jit_flag != -1)
return use_rx_jit_flag;
const char *env = getenv("MONERO_USE_RX_JIT");
if (!env) {
use_rx_jit_flag = 1;
}
else if (!strcmp(env, "0") || !strcmp(env, "no")) {
use_rx_jit_flag = 0;
}
else {
use_rx_jit_flag = 1;
}
return use_rx_jit_flag;
#else
return 0;
#endif
}
#define SEEDHASH_EPOCH_BLOCKS 2048 /* Must be same as BLOCKS_SYNCHRONIZING_MAX_COUNT in cryptonote_config.h */
#define SEEDHASH_EPOCH_LAG 64
void rx_reorg(const uint64_t split_height) {
int i;
CTHR_MUTEX_LOCK(rx_mutex);
for (i=0; i<2; i++) {
if (split_height < rx_s[i].rs_height)
rx_s[i].rs_height = 1; /* set to an invalid seed height */
}
CTHR_MUTEX_UNLOCK(rx_mutex);
}
uint64_t rx_seedheight(const uint64_t height) {
uint64_t s_height = (height <= SEEDHASH_EPOCH_BLOCKS+SEEDHASH_EPOCH_LAG) ? 0 :
(height - SEEDHASH_EPOCH_LAG - 1) & ~(SEEDHASH_EPOCH_BLOCKS-1);
return s_height;
}
void rx_seedheights(const uint64_t height, uint64_t *seedheight, uint64_t *nextheight) {
*seedheight = rx_seedheight(height);
*nextheight = rx_seedheight(height + SEEDHASH_EPOCH_LAG);
}
bool rx_needhash(const uint64_t height, uint64_t *seedheight) {
rx_state *rx_sp;
uint64_t s_height = rx_seedheight(height);
int toggle = (s_height & SEEDHASH_EPOCH_BLOCKS) != 0;
bool ret;
bool changed = (toggle != rx_s_toggle);
*seedheight = s_height;
rx_s_toggle = toggle;
rx_sp = &rx_s[rx_s_toggle];
ret = (rx_sp->rs_cache == NULL) || (rx_sp->rs_height != s_height);
/* if cache is ok but we've flipped caches, reset vm */
if (!ret && changed && rx_vm != NULL)
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache);
return ret;
}
typedef struct seedinfo {
randomx_cache *si_cache;
unsigned long si_start;
unsigned long si_count;
} seedinfo;
static CTHR_THREAD_RTYPE rx_seedthread(void *arg) {
seedinfo *si = arg;
randomx_init_dataset(rx_dataset, si->si_cache, si->si_start, si->si_count);
return NULL;
}
static void rx_initdata(randomx_cache *rs_cache, const int miners) {
if (miners > 1) {
unsigned long delta = randomx_dataset_item_count() / miners;
unsigned long start = 0;
int i;
seedinfo *si;
CTHR_THREAD_TYPE *st;
si = malloc(miners * sizeof(seedinfo));
if (si == NULL)
local_abort("Couldn't allocate RandomWOW mining threadinfo");
st = malloc(miners * sizeof(CTHR_THREAD_TYPE));
if (st == NULL) {
free(si);
local_abort("Couldn't allocate RandomWOW mining threadlist");
}
for (i=0; i<miners-1; i++) {
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = delta;
start += delta;
}
si[i].si_cache = rs_cache;
si[i].si_start = start;
si[i].si_count = randomx_dataset_item_count() - start;
for (i=1; i<miners; i++) {
CTHR_THREAD_CREATE(st[i], rx_seedthread, &si[i]);
}
randomx_init_dataset(rx_dataset, rs_cache, 0, si[0].si_count);
for (i=1; i<miners; i++) {
CTHR_THREAD_JOIN(st[i]);
}
free(st);
free(si);
} else {
randomx_init_dataset(rx_dataset, rs_cache, 0, randomx_dataset_item_count());
}
}
static void rx_seedhash_int(rx_state *rx_sp, const uint64_t height, const char *hash, const int miners) {
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
randomx_cache *cache;
CTHR_MUTEX_LOCK(rx_mutex);
cache = rx_sp->rs_cache;
if (rx_sp->rs_height != height || cache == NULL) {
if (use_rx_jit())
flags |= RANDOMX_FLAG_JIT;
if (cache == NULL) {
cache = randomx_alloc_cache(flags | RANDOMX_FLAG_LARGE_PAGES);
if (cache == NULL)
cache = randomx_alloc_cache(flags);
if (cache == NULL)
local_abort("Couldn't allocate RandomWOW cache");
}
randomx_init_cache(cache, hash, 32);
if (miners && rx_dataset != NULL)
rx_initdata(cache, miners);
rx_sp->rs_height = height;
if (rx_sp->rs_cache == NULL)
rx_sp->rs_cache = cache;
}
CTHR_MUTEX_UNLOCK(rx_mutex);
if (rx_vm != NULL)
randomx_vm_set_cache(rx_vm, rx_sp->rs_cache);
}
void rx_seedhash(const uint64_t height, const char *hash, const int miners) {
rx_state *rx_sp = &rx_s[rx_s_toggle];
rx_seedhash_int(rx_sp, height, hash, miners);
}
static char rx_althash[32]; // seedhash for alternate blocks
void rx_alt_slowhash(const uint64_t mainheight, const uint64_t seedheight, const char *seedhash, const void *data, size_t length, char *hash) {
uint64_t s_height = rx_seedheight(mainheight);
int alt_toggle = (s_height & SEEDHASH_EPOCH_BLOCKS) == 0;
rx_state *rx_sp = &rx_s[alt_toggle];
if (rx_sp->rs_height != seedheight || rx_sp->rs_cache == NULL || memcmp(hash, rx_althash, sizeof(rx_althash))) {
memcpy(rx_althash, seedhash, sizeof(rx_althash));
rx_sp->rs_height = 1;
rx_seedhash_int(rx_sp, seedheight, seedhash, 0);
}
if (rx_vm == NULL) {
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
if (use_rx_jit())
flags |= RANDOMX_FLAG_JIT;
if(!force_software_aes() && check_aes_hw())
flags |= RANDOMX_FLAG_HARD_AES;
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, NULL);
if(rx_vm == NULL) //large pages failed
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, NULL);
if(rx_vm == NULL) {//fallback if everything fails
flags = RANDOMX_FLAG_DEFAULT;
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, NULL);
}
if (rx_vm == NULL)
local_abort("Couldn't allocate RandomWOW VM");
}
randomx_calculate_hash(rx_vm, data, length, hash);
}
void rx_slow_hash(const void *data, size_t length, char *hash, int miners) {
if (rx_vm == NULL) {
rx_state *rx_sp = &rx_s[rx_s_toggle];
randomx_flags flags = RANDOMX_FLAG_DEFAULT;
if (use_rx_jit())
flags |= RANDOMX_FLAG_JIT;
if(!force_software_aes() && check_aes_hw())
flags |= RANDOMX_FLAG_HARD_AES;
if (miners) {
if (rx_dataset == NULL) {
CTHR_MUTEX_LOCK(rx_mutex);
if (rx_dataset == NULL) {
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_LARGE_PAGES);
if (rx_dataset == NULL)
rx_dataset = randomx_alloc_dataset(RANDOMX_FLAG_DEFAULT);
if (rx_dataset != NULL)
rx_initdata(rx_sp->rs_cache, miners);
}
CTHR_MUTEX_UNLOCK(rx_mutex);
}
if (rx_dataset != NULL)
flags |= RANDOMX_FLAG_FULL_MEM;
else
miners = 0;
}
rx_vm = randomx_create_vm(flags | RANDOMX_FLAG_LARGE_PAGES, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) //large pages failed
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
if(rx_vm == NULL) {//fallback if everything fails
flags = RANDOMX_FLAG_DEFAULT | (miners ? RANDOMX_FLAG_FULL_MEM : 0);
rx_vm = randomx_create_vm(flags, rx_sp->rs_cache, rx_dataset);
}
if (rx_vm == NULL)
local_abort("Couldn't allocate RandomWOW VM");
}
randomx_calculate_hash(rx_vm, data, length, hash);
}
void rx_slow_hash_allocate_state(void) {
}
void rx_slow_hash_free_state(void) {
if (rx_vm != NULL) {
randomx_destroy_vm(rx_vm);
rx_vm = NULL;
}
}

@ -653,7 +653,7 @@ BOOL SetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable)
* the allocated buffer. * the allocated buffer.
*/ */
void slow_hash_allocate_state(void) void cn_slow_hash_allocate_state(void)
{ {
if(hp_state != NULL) if(hp_state != NULL)
return; return;
@ -686,7 +686,7 @@ void slow_hash_allocate_state(void)
*@brief frees the state allocated by slow_hash_allocate_state *@brief frees the state allocated by slow_hash_allocate_state
*/ */
void slow_hash_free_state(void) void cn_slow_hash_free_state(void)
{ {
if(hp_state == NULL) if(hp_state == NULL)
return; return;
@ -760,7 +760,7 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
// this isn't supposed to happen, but guard against it for now. // this isn't supposed to happen, but guard against it for now.
if(hp_state == NULL) if(hp_state == NULL)
slow_hash_allocate_state(); cn_slow_hash_allocate_state();
/* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */ /* CryptoNight Step 1: Use Keccak1600 to initialize the 'state' (and 'text') buffers from the data. */
if (prehashed) { if (prehashed) {
@ -874,13 +874,13 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
} }
#elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__)) #elif !defined NO_AES && (defined(__arm__) || defined(__aarch64__))
void slow_hash_allocate_state(void) void cn_slow_hash_allocate_state(void)
{ {
// Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
return; return;
} }
void slow_hash_free_state(void) void cn_slow_hash_free_state(void)
{ {
// As above // As above
return; return;
@ -1440,13 +1440,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
#else #else
// Portable implementation as a fallback // Portable implementation as a fallback
void slow_hash_allocate_state(void) #define hp_jitfunc ((v4_random_math_JIT_func)NULL)
void cn_slow_hash_allocate_state(void)
{ {
// Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c
return; return;
} }
void slow_hash_free_state(void) void cn_slow_hash_free_state(void)
{ {
// As above // As above
return; return;
@ -1623,3 +1625,15 @@ void cn_slow_hash(const void *data, size_t length, char *hash, int variant, int
} }
#endif #endif
void slow_hash_allocate_state(void)
{
cn_slow_hash_allocate_state();
rx_slow_hash_allocate_state();
}
void slow_hash_free_state(void)
{
cn_slow_hash_free_state();
rx_slow_hash_free_state();
}

@ -1202,14 +1202,6 @@ namespace cryptonote
return p; return p;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
bool get_block_longhash(const block& b, crypto::hash& res, uint64_t height)
{
blobdata bd = get_block_hashing_blob(b);
const int cn_variant = b.major_version >= 11 ? 4 : b.major_version >= 9 && b.major_version <= 10 ? 2 : 1;
crypto::cn_slow_hash(bd.data(), bd.size(), res, cn_variant, height);
return true;
}
//---------------------------------------------------------------
std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off) std::vector<uint64_t> relative_output_offsets_to_absolute(const std::vector<uint64_t>& off)
{ {
std::vector<uint64_t> res = off; std::vector<uint64_t> res = off;
@ -1230,13 +1222,6 @@ namespace cryptonote
return res; 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, crypto::hash *block_hash) bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash)
{ {
std::stringstream ss; std::stringstream ss;

@ -117,8 +117,6 @@ namespace cryptonote
bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob = NULL); bool calculate_block_hash(const block& b, crypto::hash& res, const blobdata *blob = NULL);
bool get_block_hash(const block& b, crypto::hash& res); bool get_block_hash(const block& b, crypto::hash& res);
crypto::hash get_block_hash(const block& b); 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, crypto::hash *block_hash); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash *block_hash);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b, crypto::hash &block_hash);

@ -37,8 +37,10 @@
#include "syncobj.h" #include "syncobj.h"
#include "cryptonote_basic_impl.h" #include "cryptonote_basic_impl.h"
#include "cryptonote_format_utils.h" #include "cryptonote_format_utils.h"
#include "cryptonote_core/cryptonote_tx_utils.h"
#include "file_io_utils.h" #include "file_io_utils.h"
#include "common/command_line.h" #include "common/command_line.h"
#include "common/util.h"
#include "string_coding.h" #include "string_coding.h"
#include "string_tools.h" #include "string_tools.h"
#include "storages/portable_storage_template_helper.h" #include "storages/portable_storage_template_helper.h"
@ -99,12 +101,13 @@ namespace cryptonote
} }
miner::miner(i_miner_handler* phandler):m_stop(1), miner::miner(i_miner_handler* phandler, Blockchain* pbc):m_stop(1),
m_template(boost::value_initialized<block>()), m_template(boost::value_initialized<block>()),
m_template_no(0), m_template_no(0),
m_diffic(0), m_diffic(0),
m_thread_index(0), m_thread_index(0),
m_phandler(phandler), m_phandler(phandler),
m_pbc(pbc),
m_height(0), m_height(0),
m_threads_active(0), m_threads_active(0),
m_pausers_count(0), m_pausers_count(0),
@ -466,12 +469,12 @@ namespace cryptonote
return true; return true;
} }
//----------------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------------
bool miner::find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height) bool miner::find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height)
{ {
for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++) for(; bl.nonce != std::numeric_limits<uint32_t>::max(); bl.nonce++)
{ {
crypto::hash h; crypto::hash h;
get_block_longhash(bl, h, height); get_block_longhash(pbc, bl, h, height, tools::get_max_concurrency());
if(check_hash(h, diffic)) if(check_hash(h, diffic))
{ {
@ -570,7 +573,7 @@ namespace cryptonote
b.nonce = nonce; b.nonce = nonce;
crypto::hash h; crypto::hash h;
get_block_longhash(b, h, height); get_block_longhash(m_pbc, b, h, height, tools::get_max_concurrency());
if(check_hash(h, local_diff)) if(check_hash(h, local_diff))
{ {

@ -52,13 +52,15 @@ namespace cryptonote
~i_miner_handler(){}; ~i_miner_handler(){};
}; };
class Blockchain;
/************************************************************************/ /************************************************************************/
/* */ /* */
/************************************************************************/ /************************************************************************/
class miner class miner
{ {
public: public:
miner(i_miner_handler* phandler); miner(i_miner_handler* phandler, Blockchain* pbc);
~miner(); ~miner();
bool init(const boost::program_options::variables_map& vm, network_type nettype); bool init(const boost::program_options::variables_map& vm, network_type nettype);
static void init_options(boost::program_options::options_description& desc); static void init_options(boost::program_options::options_description& desc);
@ -74,7 +76,7 @@ namespace cryptonote
bool on_idle(); bool on_idle();
void on_synchronized(); void on_synchronized();
//synchronous analog (for fast calls) //synchronous analog (for fast calls)
static bool find_nonce_for_given_block(block& bl, const difficulty_type& diffic, uint64_t height); static bool find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height);
void pause(); void pause();
void resume(); void resume();
void do_print_hashrate(bool do_hr); void do_print_hashrate(bool do_hr);
@ -133,6 +135,7 @@ namespace cryptonote
std::list<boost::thread> m_threads; std::list<boost::thread> m_threads;
epee::critical_section m_threads_lock; epee::critical_section m_threads_lock;
i_miner_handler* m_phandler; i_miner_handler* m_phandler;
Blockchain* m_pbc;
account_public_address m_mine_address; 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<5> m_update_block_template_interval;
epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;

@ -103,6 +103,7 @@
#define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing #define BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT 10000 //by default, blocks ids count in synchronizing
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT_PRE_V4 100 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 20 //by default, blocks count in blocks downloading
#define BLOCKS_SYNCHRONIZING_MAX_COUNT 2048 //must be a power of 2, greater than 128, equal to SEEDHASH_EPOCH_BLOCKS
#define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days #define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days
#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week

@ -95,6 +95,8 @@ static const struct {
{ 10, 63469, 0, 1541700352 }, { 10, 63469, 0, 1541700352 },
{ 11, 81769, 0, 1549238400 }, { 11, 81769, 0, 1549238400 },
{ 12, 82069, 0, 1549318761 }, { 12, 82069, 0, 1549318761 },
{ 13, 114969, 0, 1559292691 },
{ 14, 115257, 0, 1559292774 },
}; };
static const struct { static const struct {
@ -138,7 +140,8 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
m_difficulty_for_next_block_top_hash(crypto::null_hash), m_difficulty_for_next_block_top_hash(crypto::null_hash),
m_difficulty_for_next_block(1), m_difficulty_for_next_block(1),
m_btc_valid(false), m_btc_valid(false),
m_batch_success(true) m_batch_success(true),
m_prepare_height(0)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
} }
@ -686,9 +689,9 @@ bool Blockchain::reset_and_set_genesis_block(const block& b)
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
m_timestamps_and_difficulties_height = 0; m_timestamps_and_difficulties_height = 0;
m_alternative_chains.clear();
invalidate_block_template_cache(); invalidate_block_template_cache();
m_db->reset(); m_db->reset();
m_db->drop_alt_blocks();
m_hardfork->init(); m_hardfork->init();
db_wtxn_guard wtxn_guard(m_db); db_wtxn_guard wtxn_guard(m_db);
@ -797,6 +800,13 @@ crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const
return null_hash; return null_hash;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
crypto::hash Blockchain::get_pending_block_id_by_height(uint64_t height) const
{
if (m_prepare_height && height >= m_prepare_height && height - m_prepare_height < m_prepare_nblocks)
return (*m_prepare_blocks)[height - m_prepare_height].hash;
return get_block_id_by_height(height);
}
//------------------------------------------------------------------
bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orphan) const
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
@ -813,10 +823,15 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph
// try to find block in alternative chain // try to find block in alternative chain
catch (const BLOCK_DNE& e) catch (const BLOCK_DNE& e)
{ {
blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h); alt_block_data_t data;
if (m_alternative_chains.end() != it_alt) cryptonote::blobdata blob;
if (m_db->get_alt_block(h, &data, &blob))
{ {
blk = it_alt->second.bl; if (!cryptonote::parse_and_validate_block_from_blob(blob, blk))
{
MERROR("Found block " << h << " in alt chain, but failed to parse it");
throw std::runtime_error("Found block in alt chain, but failed to parse it");
}
if (orphan) if (orphan)
*orphan = true; *orphan = true;
return true; return true;
@ -996,7 +1011,7 @@ bool Blockchain::rollback_blockchain_switching(std::list<block>& original_chain,
//------------------------------------------------------------------ //------------------------------------------------------------------
// This function attempts to switch to an alternate chain, returning // This function attempts to switch to an alternate chain, returning
// boolean based on success therein. // boolean based on success therein.
bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain, bool discard_disconnected_chain) bool Blockchain::switch_to_alternative_blockchain(std::list<block_extended_info>& alt_chain, bool discard_disconnected_chain)
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
@ -1007,7 +1022,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed"); CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed");
// verify that main chain has front of alt chain's parent block // verify that main chain has front of alt chain's parent block
if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) if (!m_db->block_exists(alt_chain.front().bl.prev_id))
{ {
LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!"); LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!");
return false; return false;
@ -1016,7 +1031,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// pop blocks from the blockchain until the top block is the parent // pop blocks from the blockchain until the top block is the parent
// of the front block of the alt chain. // of the front block of the alt chain.
std::list<block> disconnected_chain; std::list<block> disconnected_chain;
while (m_db->top_block_hash() != alt_chain.front()->second.bl.prev_id) while (m_db->top_block_hash() != alt_chain.front().bl.prev_id)
{ {
block b = pop_block_from_blockchain(); block b = pop_block_from_blockchain();
disconnected_chain.push_front(b); disconnected_chain.push_front(b);
@ -1027,11 +1042,11 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
//connecting new alternative chain //connecting new alternative chain
for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++) for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++)
{ {
auto ch_ent = *alt_ch_iter; const auto &bei = *alt_ch_iter;
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
// add block to main chain // add block to main chain
bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc); bool r = handle_block_to_main_chain(bei.bl, bvc);
// if adding block to main chain failed, rollback to previous state and // if adding block to main chain failed, rollback to previous state and
// return false // return false
@ -1047,14 +1062,18 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// FIXME: Why do we keep invalid blocks around? Possibly in case we hear // FIXME: Why do we keep invalid blocks around? Possibly in case we hear
// about them again so we can immediately dismiss them, but needs some // about them again so we can immediately dismiss them, but needs some
// looking into. // looking into.
add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl)); const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl)); add_block_as_invalid(bei, blkid);
m_alternative_chains.erase(*alt_ch_iter++); MERROR("The block was inserted as invalid while connecting new alternative chain, block_id: " << blkid);
m_db->remove_alt_block(blkid);
alt_ch_iter++;
for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); ) for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
{ {
add_block_as_invalid((*alt_ch_to_orph_iter)->second, (*alt_ch_to_orph_iter)->first); const auto &bei = *alt_ch_to_orph_iter++;
m_alternative_chains.erase(*alt_ch_to_orph_iter++); const crypto::hash blkid = cryptonote::get_block_hash(bei.bl);
add_block_as_invalid(bei, blkid);
m_db->remove_alt_block(blkid);
} }
return false; return false;
} }
@ -1079,12 +1098,13 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
} }
//removing alt_chain entries from alternative chains container //removing alt_chain entries from alternative chains container
for (auto ch_ent: alt_chain) for (const auto &bei: alt_chain)
{ {
m_alternative_chains.erase(ch_ent); m_db->remove_alt_block(cryptonote::get_block_hash(bei.bl));
} }
m_hardfork->reorganize_from_chain_height(split_height); m_hardfork->reorganize_from_chain_height(split_height);
get_block_longhash_reorg(split_height);
std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify; std::shared_ptr<tools::Notify> reorg_notify = m_reorg_notify;
if (reorg_notify) if (reorg_notify)
@ -1097,7 +1117,7 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
//------------------------------------------------------------------ //------------------------------------------------------------------
// This function calculates the difficulty target for the block being added to // This function calculates the difficulty target for the block being added to
// an alternate chain. // an alternate chain.
difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei) const difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<block_extended_info>& alt_chain, block_extended_info& bei) const
{ {
if (m_fixed_difficulty) if (m_fixed_difficulty)
{ {
@ -1119,7 +1139,7 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
// Figure out start and stop offsets for main chain blocks // Figure out start and stop offsets for main chain blocks
size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height; size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front().height : bei.height;
size_t main_chain_count = difficulty_blocks_count - std::min(static_cast<size_t>(difficulty_blocks_count), alt_chain.size()); size_t main_chain_count = difficulty_blocks_count - std::min(static_cast<size_t>(difficulty_blocks_count), alt_chain.size());
main_chain_count = std::min(main_chain_count, main_chain_stop_offset); main_chain_count = std::min(main_chain_count, main_chain_stop_offset);
size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count; size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count;
@ -1137,10 +1157,10 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
// make sure we haven't accidentally grabbed too many blocks...maybe don't need this check? // make sure we haven't accidentally grabbed too many blocks...maybe don't need this check?
CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficulty_blocks_count, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficulty_blocks_count); CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= difficulty_blocks_count, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << difficulty_blocks_count);
for (auto it : alt_chain) for (const auto &bei : alt_chain)
{ {
timestamps.push_back(it->second.bl.timestamp); timestamps.push_back(bei.bl.timestamp);
cumulative_difficulties.push_back(it->second.cumulative_difficulty); cumulative_difficulties.push_back(bei.cumulative_difficulty);
} }
} }
// if the alt chain is long enough for the difficulty calc, grab difficulties // if the alt chain is long enough for the difficulty calc, grab difficulties
@ -1152,10 +1172,10 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
size_t count = 0; size_t count = 0;
size_t max_i = timestamps.size()-1; size_t max_i = timestamps.size()-1;
// get difficulties and timestamps from most recent blocks in alt chain // get difficulties and timestamps from most recent blocks in alt chain
for(auto it: boost::adaptors::reverse(alt_chain)) for (const auto bei: boost::adaptors::reverse(alt_chain))
{ {
timestamps[max_i - count] = it->second.bl.timestamp; timestamps[max_i - count] = bei.bl.timestamp;
cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty; cumulative_difficulties[max_i - count] = bei.cumulative_difficulty;
count++; count++;
if(count >= difficulty_blocks_count) if(count >= difficulty_blocks_count)
break; break;
@ -1389,16 +1409,17 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
//build alternative subchain, front -> mainchain, back -> alternative head //build alternative subchain, front -> mainchain, back -> alternative head
//block is not related with head of main chain //block is not related with head of main chain
//first of all - look in alternative chains container //first of all - look in alternative chains container
auto it_prev = m_alternative_chains.find(*from_block); alt_block_data_t prev_data;
bool parent_in_alt = m_db->get_alt_block(*from_block, &prev_data, NULL);
bool parent_in_main = m_db->block_exists(*from_block); bool parent_in_main = m_db->block_exists(*from_block);
if(it_prev == m_alternative_chains.end() && !parent_in_main) if (!parent_in_alt && !parent_in_main)
{ {
MERROR("Unknown from block"); MERROR("Unknown from block");
return false; return false;
} }
//we have new block in alternative chain //we have new block in alternative chain
std::list<blocks_ext_by_hash::const_iterator> alt_chain; std::list<block_extended_info> alt_chain;
block_verification_context bvc = boost::value_initialized<block_verification_context>(); block_verification_context bvc = boost::value_initialized<block_verification_context>();
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc)) if (!build_alt_chain(*from_block, alt_chain, timestamps, bvc))
@ -1413,7 +1434,7 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
} }
else else
{ {
height = alt_chain.back()->second.height + 1; height = alt_chain.back().height + 1;
} }
b.major_version = m_hardfork->get_ideal_version(height); b.major_version = m_hardfork->get_ideal_version(height);
b.minor_version = m_hardfork->get_ideal_version(); b.minor_version = m_hardfork->get_ideal_version();
@ -1428,14 +1449,14 @@ bool Blockchain::create_block_template(block& b, const crypto::hash *from_block,
} }
else else
{ {
median_weight = it_prev->second.block_cumulative_weight - it_prev->second.block_cumulative_weight / 20; median_weight = prev_data.cumulative_weight - prev_data.cumulative_weight / 20;
already_generated_coins = alt_chain.back()->second.already_generated_coins; already_generated_coins = alt_chain.back().already_generated_coins;
} }
// FIXME: consider moving away from block_extended_info at some point // FIXME: consider moving away from block_extended_info at some point
block_extended_info bei = boost::value_initialized<block_extended_info>(); block_extended_info bei = boost::value_initialized<block_extended_info>();
bei.bl = b; bei.bl = b;
bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(*from_block) + 1; bei.height = alt_chain.size() ? prev_data.height + 1 : m_db->get_block_height(*from_block) + 1;
diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei); diffic = get_next_difficulty_for_alternative_chain(alt_chain, bei);
} }
@ -1615,16 +1636,25 @@ bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vect
return true; return true;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<block_extended_info>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const
{ {
//build alternative subchain, front -> mainchain, back -> alternative head //build alternative subchain, front -> mainchain, back -> alternative head
blocks_ext_by_hash::const_iterator alt_it = m_alternative_chains.find(prev_id); cryptonote::alt_block_data_t data;
cryptonote::blobdata blob;
bool found = m_db->get_alt_block(prev_id, &data, &blob);
timestamps.clear(); timestamps.clear();
while(alt_it != m_alternative_chains.end()) while(found)
{ {
alt_chain.push_front(alt_it); block_extended_info bei;
timestamps.push_back(alt_it->second.bl.timestamp); CHECK_AND_ASSERT_MES(cryptonote::parse_and_validate_block_from_blob(blob, bei.bl), false, "Failed to parse alt block");
alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id); bei.height = data.height;
bei.block_cumulative_weight = data.cumulative_weight;
bei.cumulative_difficulty = data.cumulative_difficulty_high;
bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + data.cumulative_difficulty_low;
bei.already_generated_coins = data.already_generated_coins;
timestamps.push_back(bei.bl.timestamp);
alt_chain.push_front(std::move(bei));
found = m_db->get_alt_block(bei.bl.prev_id, &data, &blob);
} }
// if block to be added connects to known blocks that aren't part of the // if block to be added connects to known blocks that aren't part of the
@ -1632,20 +1662,20 @@ bool Blockchain::build_alt_chain(const crypto::hash &prev_id, std::list<blocks_e
if(!alt_chain.empty()) if(!alt_chain.empty())
{ {
// make sure alt chain doesn't somehow start past the end of the main chain // make sure alt chain doesn't somehow start past the end of the main chain
CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front()->second.height, false, "main blockchain wrong height"); CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front().height, false, "main blockchain wrong height");
// make sure that the blockchain contains the block that should connect // make sure that the blockchain contains the block that should connect
// this alternate chain with it. // this alternate chain with it.
if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) if (!m_db->block_exists(alt_chain.front().bl.prev_id))
{ {
MERROR("alternate chain does not appear to connect to main chain..."); MERROR("alternate chain does not appear to connect to main chain...");
return false; return false;
} }
// make sure block connects correctly to the main chain // make sure block connects correctly to the main chain
auto h = m_db->get_block_hash_from_height(alt_chain.front()->second.height - 1); auto h = m_db->get_block_hash_from_height(alt_chain.front().height - 1);
CHECK_AND_ASSERT_MES(h == alt_chain.front()->second.bl.prev_id, false, "alternative chain has wrong connection to main chain"); CHECK_AND_ASSERT_MES(h == alt_chain.front().bl.prev_id, false, "alternative chain has wrong connection to main chain");
complete_timestamps_vector(m_db->get_block_height(alt_chain.front()->second.bl.prev_id), timestamps); complete_timestamps_vector(m_db->get_block_height(alt_chain.front().bl.prev_id), timestamps);
} }
// if block not associated with known alternate chain // if block not associated with known alternate chain
else else
@ -1700,12 +1730,13 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
//block is not related with head of main chain //block is not related with head of main chain
//first of all - look in alternative chains container //first of all - look in alternative chains container
auto it_prev = m_alternative_chains.find(b.prev_id); alt_block_data_t prev_data;
bool parent_in_alt = m_db->get_alt_block(b.prev_id, &prev_data, NULL);
bool parent_in_main = m_db->block_exists(b.prev_id); bool parent_in_main = m_db->block_exists(b.prev_id);
if(it_prev != m_alternative_chains.end() || parent_in_main) if (parent_in_alt || parent_in_main)
{ {
//we have new block in alternative chain //we have new block in alternative chain
std::list<blocks_ext_by_hash::const_iterator> alt_chain; std::list<block_extended_info> alt_chain;
std::vector<uint64_t> timestamps; std::vector<uint64_t> timestamps;
if (!build_alt_chain(b.prev_id, alt_chain, timestamps, bvc)) if (!build_alt_chain(b.prev_id, alt_chain, timestamps, bvc))
return false; return false;
@ -1713,10 +1744,10 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
// FIXME: consider moving away from block_extended_info at some point // FIXME: consider moving away from block_extended_info at some point
block_extended_info bei = boost::value_initialized<block_extended_info>(); block_extended_info bei = boost::value_initialized<block_extended_info>();
bei.bl = b; bei.bl = b;
const uint64_t prev_height = alt_chain.size() ? it_prev->second.height : m_db->get_block_height(b.prev_id); const uint64_t prev_height = alt_chain.size() ? prev_data.height : m_db->get_block_height(b.prev_id);
bei.height = prev_height + 1; bei.height = prev_height + 1;
uint64_t block_reward = get_outs_money_amount(b.miner_tx); uint64_t block_reward = get_outs_money_amount(b.miner_tx);
bei.already_generated_coins = block_reward + (alt_chain.size() ? it_prev->second.already_generated_coins : m_db->get_block_already_generated_coins(prev_height)); bei.already_generated_coins = block_reward + (alt_chain.size() ? prev_data.already_generated_coins : m_db->get_block_already_generated_coins(prev_height));
// verify that the block's timestamp is within the acceptable range // verify that the block's timestamp is within the acceptable range
// (not earlier than the median of the last X blocks) // (not earlier than the median of the last X blocks)
@ -1739,7 +1770,30 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei); difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei);
CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!");
crypto::hash proof_of_work = null_hash; crypto::hash proof_of_work = null_hash;
get_block_longhash(bei.bl, proof_of_work, bei.height); if (b.major_version >= RX_BLOCK_VERSION)
{
crypto::hash seedhash = null_hash;
uint64_t seedheight = rx_seedheight(bei.height);
// seedblock is on the alt chain somewhere
if (alt_chain.size() && alt_chain.front().height <= seedheight)
{
for (auto it=alt_chain.begin(); it != alt_chain.end(); it++)
{
if (it->height == seedheight+1)
{
seedhash = it->bl.prev_id;
break;
}
}
} else
{
seedhash = get_block_id_by_height(seedheight);
}
get_altblock_longhash(bei.bl, proof_of_work, get_current_blockchain_height(), bei.height, seedheight, seedhash);
} else
{
get_block_longhash(this, bei.bl, proof_of_work, bei.height, 0);
}
if(!check_hash(proof_of_work, current_diff)) if(!check_hash(proof_of_work, current_diff))
{ {
MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff); MERROR_VER("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff);
@ -1760,7 +1814,8 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1); difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1);
if (alt_chain.size()) if (alt_chain.size())
{ {
bei.cumulative_difficulty = it_prev->second.cumulative_difficulty; bei.cumulative_difficulty = prev_data.cumulative_difficulty_high;
bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + prev_data.cumulative_difficulty_low;
} }
else else
{ {
@ -1771,15 +1826,21 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
// add block to alternate blocks storage, // add block to alternate blocks storage,
// as well as the current "alt chain" container // as well as the current "alt chain" container
auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei)); CHECK_AND_ASSERT_MES(!m_db->get_alt_block(id, NULL, NULL), false, "insertion of new alternative block returned as it already exists");
CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist"); cryptonote::alt_block_data_t data;
alt_chain.push_back(i_res.first); data.height = bei.height;
data.cumulative_weight = bei.block_cumulative_weight;
data.cumulative_difficulty_low = (bei.cumulative_difficulty & 0xffffffffffffffff).convert_to<uint64_t>();
data.cumulative_difficulty_high = ((bei.cumulative_difficulty >> 64) & 0xffffffffffffffff).convert_to<uint64_t>();
data.already_generated_coins = bei.already_generated_coins;
m_db->add_alt_block(id, data, cryptonote::block_to_blob(bei.bl));
alt_chain.push_back(bei);
// FIXME: is it even possible for a checkpoint to show up not on the main chain? // FIXME: is it even possible for a checkpoint to show up not on the main chain?
if(is_a_checkpoint) if(is_a_checkpoint)
{ {
//do reorganize! //do reorganize!
MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height); MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front().height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height);
bool r = switch_to_alternative_blockchain(alt_chain, true); bool r = switch_to_alternative_blockchain(alt_chain, true);
@ -1791,7 +1852,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain
{ {
//do reorganize! //do reorganize!
MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty); MGINFO_GREEN("###### REORGANIZE on height: " << alt_chain.front().height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty);
bool r = switch_to_alternative_blockchain(alt_chain, false); bool r = switch_to_alternative_blockchain(alt_chain, false);
if (r) if (r)
@ -1811,7 +1872,7 @@ bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id
//block orphaned //block orphaned
bvc.m_marked_as_orphaned = true; bvc.m_marked_as_orphaned = true;
MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height MERROR_VER("Block recognized as orphaned and rejected, id = " << id << ", height " << block_height
<< ", parent in alt " << (it_prev != m_alternative_chains.end()) << ", parent in main " << parent_in_main << ", parent in alt " << parent_in_alt << ", parent in main " << parent_in_main
<< " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")"); << " (parent " << b.prev_id << ", current top " << get_tail_id() << ", chain height " << get_current_blockchain_height() << ")");
} }
@ -1916,11 +1977,20 @@ bool Blockchain::get_alternative_blocks(std::vector<block>& blocks) const
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
blocks.reserve(m_alternative_chains.size()); blocks.reserve(m_db->get_alt_block_count());
for (const auto& alt_bl: m_alternative_chains) m_db->for_all_alt_blocks([&blocks](const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata *blob) {
{ if (!blob)
blocks.push_back(alt_bl.second.bl); {
} MERROR("No blob, but blobs were requested");
return false;
}
cryptonote::block bl;
if (cryptonote::parse_and_validate_block_from_blob(*blob, bl))
blocks.push_back(std::move(bl));
else
MERROR("Failed to parse block from blob");
return true;
}, true);
return true; return true;
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -1928,7 +1998,7 @@ size_t Blockchain::get_alternative_blocks_count() const
{ {
LOG_PRINT_L3("Blockchain::" << __func__); LOG_PRINT_L3("Blockchain::" << __func__);
CRITICAL_REGION_LOCAL(m_blockchain_lock); CRITICAL_REGION_LOCAL(m_blockchain_lock);
return m_alternative_chains.size(); return m_db->get_alt_block_count();
} }
//------------------------------------------------------------------ //------------------------------------------------------------------
// This function adds the output specified by <amount, i> to the result_outs container // This function adds the output specified by <amount, i> to the result_outs container
@ -2416,9 +2486,9 @@ bool Blockchain::have_block(const crypto::hash& id) const
return true; return true;
} }
if(m_alternative_chains.count(id)) if(m_db->get_alt_block(id, NULL, NULL))
{ {
LOG_PRINT_L2("block " << id << " found in m_alternative_chains"); LOG_PRINT_L2("block " << id << " found in alternative chains");
return true; return true;
} }
@ -3660,7 +3730,7 @@ leave:
proof_of_work = it->second; proof_of_work = it->second;
} }
else else
proof_of_work = get_block_longhash(bl, blockchain_height); proof_of_work = get_block_longhash(this, bl, blockchain_height, 0);
// validate proof_of_work versus difficulty target // validate proof_of_work versus difficulty target
if(!check_hash(proof_of_work, current_diffic)) if(!check_hash(proof_of_work, current_diffic))
@ -4163,7 +4233,7 @@ void Blockchain::block_longhash_worker(uint64_t height, const epee::span<const b
if (m_cancel) if (m_cancel)
break; break;
crypto::hash id = get_block_hash(block); crypto::hash id = get_block_hash(block);
crypto::hash pow = get_block_longhash(block, height++); crypto::hash pow = get_block_longhash(this, block, height++, 0);
map.emplace(id, pow); map.emplace(id, pow);
} }
@ -4480,6 +4550,9 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
m_blocks_longhash_table.clear(); m_blocks_longhash_table.clear();
uint64_t thread_height = height; uint64_t thread_height = height;
tools::threadpool::waiter waiter; tools::threadpool::waiter waiter;
m_prepare_height = height;
m_prepare_nblocks = blocks_entry.size();
m_prepare_blocks = &blocks;
for (unsigned int i = 0; i < threads; i++) for (unsigned int i = 0; i < threads; i++)
{ {
unsigned nblocks = batches; unsigned nblocks = batches;
@ -4490,6 +4563,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::vector<block_complete
} }
waiter.wait(&tpool); waiter.wait(&tpool);
m_prepare_height = 0;
if (m_cancel) if (m_cancel)
return false; return false;
@ -4827,11 +4901,35 @@ std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>>
{ {
std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains; std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains;
for (const auto &i: m_alternative_chains) blocks_ext_by_hash alt_blocks;
alt_blocks.reserve(m_db->get_alt_block_count());
m_db->for_all_alt_blocks([&alt_blocks](const crypto::hash &blkid, const cryptonote::alt_block_data_t &data, const cryptonote::blobdata *blob) {
if (!blob)
{
MERROR("No blob, but blobs were requested");
return false;
}
cryptonote::block bl;
block_extended_info bei;
if (cryptonote::parse_and_validate_block_from_blob(*blob, bei.bl))
{
bei.height = data.height;
bei.block_cumulative_weight = data.cumulative_weight;
bei.cumulative_difficulty = data.cumulative_difficulty_high;
bei.cumulative_difficulty = (bei.cumulative_difficulty << 64) + data.cumulative_difficulty_low;
bei.already_generated_coins = data.already_generated_coins;
alt_blocks.insert(std::make_pair(cryptonote::get_block_hash(bei.bl), std::move(bei)));
}
else
MERROR("Failed to parse block from blob");
return true;
}, true);
for (const auto &i: alt_blocks)
{ {
const crypto::hash &top = i.first; const crypto::hash top = cryptonote::get_block_hash(i.second.bl);
bool found = false; bool found = false;
for (const auto &j: m_alternative_chains) for (const auto &j: alt_blocks)
{ {
if (j.second.bl.prev_id == top) if (j.second.bl.prev_id == top)
{ {
@ -4845,7 +4943,7 @@ std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>>
auto h = i.second.bl.prev_id; auto h = i.second.bl.prev_id;
chain.push_back(top); chain.push_back(top);
blocks_ext_by_hash::const_iterator prev; blocks_ext_by_hash::const_iterator prev;
while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end()) while ((prev = alt_blocks.find(h)) != alt_blocks.end())
{ {
chain.push_back(h); chain.push_back(h);
h = prev->second.bl.prev_id; h = prev->second.bl.prev_id;

@ -91,17 +91,6 @@ namespace cryptonote
class Blockchain class Blockchain
{ {
public: public:
/**
* @brief Now-defunct (TODO: remove) struct from in-memory blockchain
*/
struct transaction_chain_entry
{
transaction tx;
uint64_t m_keeper_block_height;
size_t m_blob_size;
std::vector<uint64_t> m_global_output_indexes;
};
/** /**
* @brief container for passing a block and metadata about it on the blockchain * @brief container for passing a block and metadata about it on the blockchain
*/ */
@ -109,7 +98,7 @@ namespace cryptonote
{ {
block bl; //!< the block block bl; //!< the block
uint64_t height; //!< the height of the block in the blockchain uint64_t height; //!< the height of the block in the blockchain
size_t block_cumulative_weight; //!< the weight of the block uint64_t block_cumulative_weight; //!< the weight of the block
difficulty_type cumulative_difficulty; //!< the accumulated difficulty after that block difficulty_type cumulative_difficulty; //!< the accumulated difficulty after that block
uint64_t already_generated_coins; //!< the total coins minted after that block uint64_t already_generated_coins; //!< the total coins minted after that block
}; };
@ -216,6 +205,18 @@ namespace cryptonote
*/ */
crypto::hash get_block_id_by_height(uint64_t height) const; crypto::hash get_block_id_by_height(uint64_t height) const;
/**
* @brief gets a block's hash given a height
*
* Used only by prepare_handle_incoming_blocks. Will look in the list of incoming blocks
* if the height is contained there.
*
* @param height the height of the block
*
* @return the hash of the block at the requested height, or a zeroed hash if there is no such block
*/
crypto::hash get_pending_block_id_by_height(uint64_t height) const;
/** /**
* @brief gets the block with a given hash * @brief gets the block with a given hash
* *
@ -1011,20 +1012,12 @@ namespace cryptonote
#endif #endif
// TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage
typedef std::unordered_map<crypto::hash, size_t> blocks_by_id_index;
typedef std::unordered_map<crypto::hash, transaction_chain_entry> transactions_container;
typedef std::unordered_set<crypto::key_image> key_images_container; typedef std::unordered_set<crypto::key_image> key_images_container;
typedef std::vector<block_extended_info> blocks_container; typedef std::vector<block_extended_info> blocks_container;
typedef std::unordered_map<crypto::hash, block_extended_info> blocks_ext_by_hash; typedef std::unordered_map<crypto::hash, block_extended_info> blocks_ext_by_hash;
typedef std::unordered_map<crypto::hash, block> blocks_by_hash;
typedef std::map<uint64_t, std::vector<std::pair<crypto::hash, size_t>>> outputs_container; //crypto::hash - tx hash, size_t - index of out in transaction
BlockchainDB* m_db; BlockchainDB* m_db;
@ -1033,7 +1026,6 @@ namespace cryptonote
mutable epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock mutable epee::critical_section m_blockchain_lock; // TODO: add here reader/writer lock
// main chain // main chain
transactions_container m_transactions;
size_t m_current_block_cumul_weight_limit; size_t m_current_block_cumul_weight_limit;
size_t m_current_block_cumul_weight_median; size_t m_current_block_cumul_weight_median;
@ -1074,9 +1066,6 @@ namespace cryptonote
boost::thread_group m_async_pool; boost::thread_group m_async_pool;
std::unique_ptr<boost::asio::io_service::work> m_async_work_idle; std::unique_ptr<boost::asio::io_service::work> m_async_work_idle;
// all alternative chains
blocks_ext_by_hash m_alternative_chains; // crypto::hash -> block_extended_info
// some invalid blocks // some invalid blocks
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
@ -1108,6 +1097,11 @@ namespace cryptonote
std::shared_ptr<tools::Notify> m_block_notify; std::shared_ptr<tools::Notify> m_block_notify;
std::shared_ptr<tools::Notify> m_reorg_notify; std::shared_ptr<tools::Notify> m_reorg_notify;
// for prepare_handle_incoming_blocks
uint64_t m_prepare_height;
uint64_t m_prepare_nblocks;
std::vector<block> *m_prepare_blocks;
/** /**
* @brief collects the keys for all outputs being "spent" as an input * @brief collects the keys for all outputs being "spent" as an input
* *
@ -1186,7 +1180,7 @@ namespace cryptonote
* *
* @return false if the reorganization fails, otherwise true * @return false if the reorganization fails, otherwise true
*/ */
bool switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::const_iterator>& alt_chain, bool discard_disconnected_chain); bool switch_to_alternative_blockchain(std::list<block_extended_info>& alt_chain, bool discard_disconnected_chain);
/** /**
* @brief removes the most recent block from the blockchain * @brief removes the most recent block from the blockchain
@ -1249,7 +1243,7 @@ namespace cryptonote
* *
* @return true on success, false otherwise * @return true on success, false otherwise
*/ */
bool build_alt_chain(const crypto::hash &prev_id, std::list<blocks_ext_by_hash::const_iterator>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const; bool build_alt_chain(const crypto::hash &prev_id, std::list<block_extended_info>& alt_chain, std::vector<uint64_t> &timestamps, block_verification_context& bvc) const;
/** /**
* @brief gets the difficulty requirement for a new block on an alternate chain * @brief gets the difficulty requirement for a new block on an alternate chain
@ -1259,7 +1253,7 @@ namespace cryptonote
* *
* @return the difficulty requirement * @return the difficulty requirement
*/ */
difficulty_type get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::const_iterator>& alt_chain, block_extended_info& bei) const; difficulty_type get_next_difficulty_for_alternative_chain(const std::list<block_extended_info>& alt_chain, block_extended_info& bei) const;
/** /**
* @brief sanity checks a miner transaction before validating an entire block * @brief sanity checks a miner transaction before validating an entire block

@ -208,12 +208,17 @@ namespace cryptonote
"is acted upon." "is acted upon."
, "" , ""
}; };
static const command_line::arg_descriptor<bool> arg_keep_alt_blocks = {
"keep-alt-blocks"
, "Keep alternative blocks on restart"
, false
};
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
core::core(i_cryptonote_protocol* pprotocol): core::core(i_cryptonote_protocol* pprotocol):
m_mempool(m_blockchain_storage), m_mempool(m_blockchain_storage),
m_blockchain_storage(m_mempool), m_blockchain_storage(m_mempool),
m_miner(this), m_miner(this, &m_blockchain_storage),
m_miner_address(boost::value_initialized<account_public_address>()), m_miner_address(boost::value_initialized<account_public_address>()),
m_starter_message_showed(false), m_starter_message_showed(false),
m_target_blockchain_height(0), m_target_blockchain_height(0),
@ -325,6 +330,7 @@ namespace cryptonote
command_line::add_arg(desc, arg_prune_blockchain); command_line::add_arg(desc, arg_prune_blockchain);
command_line::add_arg(desc, arg_reorg_notify); command_line::add_arg(desc, arg_reorg_notify);
command_line::add_arg(desc, arg_block_rate_notify); command_line::add_arg(desc, arg_block_rate_notify);
command_line::add_arg(desc, arg_keep_alt_blocks);
miner::init_options(desc); miner::init_options(desc);
BlockchainDB::init_options(desc); BlockchainDB::init_options(desc);
@ -456,6 +462,7 @@ namespace cryptonote
std::string check_updates_string = command_line::get_arg(vm, arg_check_updates); std::string check_updates_string = command_line::get_arg(vm, arg_check_updates);
size_t max_txpool_weight = command_line::get_arg(vm, arg_max_txpool_weight); size_t max_txpool_weight = command_line::get_arg(vm, arg_max_txpool_weight);
bool prune_blockchain = command_line::get_arg(vm, arg_prune_blockchain); bool prune_blockchain = command_line::get_arg(vm, arg_prune_blockchain);
bool keep_alt_blocks = command_line::get_arg(vm, arg_keep_alt_blocks);
boost::filesystem::path folder(m_config_folder); boost::filesystem::path folder(m_config_folder);
if (m_nettype == FAKECHAIN) if (m_nettype == FAKECHAIN)
@ -647,6 +654,8 @@ namespace cryptonote
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize blockchain storage");
block_sync_size = command_line::get_arg(vm, arg_block_sync_size); block_sync_size = command_line::get_arg(vm, arg_block_sync_size);
if (block_sync_size > BLOCKS_SYNCHRONIZING_MAX_COUNT)
MERROR("Error --dblock-sync-size cannot be greater than " << BLOCKS_SYNCHRONIZING_MAX_COUNT);
MGINFO("Loading checkpoints"); MGINFO("Loading checkpoints");
@ -671,6 +680,9 @@ namespace cryptonote
r = m_miner.init(vm, m_nettype); r = m_miner.init(vm, m_nettype);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance"); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize miner instance");
if (!keep_alt_blocks && !m_blockchain_storage.get_db().is_read_only())
m_blockchain_storage.get_db().drop_alt_blocks();
if (prune_blockchain) if (prune_blockchain)
{ {
// display a message if the blockchain is not pruned yet // display a message if the blockchain is not pruned yet
@ -1161,7 +1173,7 @@ namespace cryptonote
//----------------------------------------------------------------------------------------------- //-----------------------------------------------------------------------------------------------
size_t core::get_block_sync_size(uint64_t height) const size_t core::get_block_sync_size(uint64_t height) const
{ {
static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 1220516 : 0; static const uint64_t quick_height = m_nettype == TESTNET ? 801219 : m_nettype == MAINNET ? 53666 : 0;
if (block_sync_size > 0) if (block_sync_size > 0)
return block_sync_size; return block_sync_size;
if (height >= quick_height) if (height >= quick_height)

@ -37,6 +37,7 @@ using namespace epee;
#include "common/apply_permutation.h" #include "common/apply_permutation.h"
#include "cryptonote_tx_utils.h" #include "cryptonote_tx_utils.h"
#include "cryptonote_config.h" #include "cryptonote_config.h"
#include "blockchain.h"
#include "cryptonote_basic/miner.h" #include "cryptonote_basic/miner.h"
#include "cryptonote_basic/tx_extra.h" #include "cryptonote_basic/tx_extra.h"
#include "crypto/crypto.h" #include "crypto/crypto.h"
@ -660,9 +661,47 @@ namespace cryptonote
bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; bl.minor_version = CURRENT_BLOCK_MINOR_VERSION;
bl.timestamp = 0; bl.timestamp = 0;
bl.nonce = nonce; bl.nonce = nonce;
miner::find_nonce_for_given_block(bl, 1, 0); miner::find_nonce_for_given_block(NULL, bl, 1, 0);
bl.invalidate_hashes(); bl.invalidate_hashes();
return true; return true;
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash)
{
blobdata bd = get_block_hashing_blob(b);
rx_alt_slowhash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data);
}
bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners)
{
blobdata bd = get_block_hashing_blob(b);
const int pow_variant = b.major_version >= 13 ? 6 : b.major_version >= 11 && b.major_version <= 12 ? 4 : 2;
if (pow_variant >= 6) {
uint64_t seed_height;
if (rx_needhash(height, &seed_height)) {
crypto::hash hash;
if (pbc != NULL)
hash = pbc->get_pending_block_id_by_height(seed_height);
else
memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block
rx_seedhash(seed_height, hash.data, miners);
}
rx_slow_hash(bd.data(), bd.size(), res.data, miners);
} else {
crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant, height);
}
return true;
}
crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners)
{
crypto::hash p = crypto::null_hash;
get_block_longhash(pbc, b, p, height, miners);
return p;
}
void get_block_longhash_reorg(const uint64_t split_height)
{
rx_reorg(split_height);
}
} }

@ -117,6 +117,13 @@ namespace cryptonote
, uint32_t nonce , uint32_t nonce
); );
class Blockchain;
bool get_block_longhash(const Blockchain *pb, const block& b, crypto::hash& res, const uint64_t height, const int miners);
void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height,
const uint64_t seed_height, const crypto::hash& seed_hash);
crypto::hash get_block_longhash(const Blockchain *pb, const block& b, const uint64_t height, const int miners);
void get_block_longhash_reorg(const uint64_t split_height);
} }
BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 1) BOOST_CLASS_VERSION(cryptonote::tx_source_entry, 1)

@ -962,13 +962,14 @@ namespace cryptonote
const account_public_address& lMiningAdr = lMiner.get_mining_address(); const account_public_address& lMiningAdr = lMiner.get_mining_address();
res.address = get_account_address_as_str(nettype(), false, lMiningAdr); res.address = get_account_address_as_str(nettype(), false, lMiningAdr);
const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version(); const uint8_t major_version = m_core.get_blockchain_storage().get_current_hard_fork_version();
const unsigned variant = major_version >= 7 ? major_version - 6 : 0; const unsigned variant = major_version >= 13 ? 6 : major_version >= 11 && major_version <= 12 ? 4 : 2;
switch (variant) switch (variant)
{ {
case 0: res.pow_algorithm = "Cryptonight"; break; case 0: res.pow_algorithm = "Cryptonight"; break;
case 1: res.pow_algorithm = "CNv1 (Cryptonight variant 1)"; break; case 1: res.pow_algorithm = "CNv1 (Cryptonight variant 1)"; break;
case 2: case 3: res.pow_algorithm = "CNv2 (Cryptonight variant 2)"; break; case 2: case 3: res.pow_algorithm = "CNv2 (Cryptonight variant 2)"; break;
case 4: case 5: res.pow_algorithm = "CNv4 (Cryptonight variant 4)"; break; case 4: case 5: res.pow_algorithm = "CN/WOW"; break;
case 6: res.pow_algorithm = "RandomWOW"; break;
default: res.pow_algorithm = "I'm not sure actually"; break; default: res.pow_algorithm = "I'm not sure actually"; break;
} }
if (res.is_background_mining_enabled) if (res.is_background_mining_enabled)
@ -1252,6 +1253,18 @@ namespace cryptonote
LOG_ERROR("Failed to create block template"); LOG_ERROR("Failed to create block template");
return false; return false;
} }
if (b.major_version >= RX_BLOCK_VERSION)
{
uint64_t seed_height, next_height;
crypto::hash seed_hash;
crypto::rx_seedheights(res.height, &seed_height, &next_height);
seed_hash = m_core.get_block_id_by_height(seed_height);
res.seed_hash = string_tools::pod_to_hex(seed_hash);
if (next_height != seed_height) {
seed_hash = m_core.get_block_id_by_height(next_height);
res.next_seed_hash = string_tools::pod_to_hex(seed_hash);
}
}
store_difficulty(wdiff, res.difficulty, res.wide_difficulty, res.difficulty_top64); store_difficulty(wdiff, res.difficulty, res.wide_difficulty, res.difficulty_top64);
blobdata block_blob = t_serializable_object_to_blob(b); blobdata block_blob = t_serializable_object_to_blob(b);
crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx); crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
@ -1394,7 +1407,7 @@ namespace cryptonote
return false; return false;
} }
b.nonce = req.starting_nonce; b.nonce = req.starting_nonce;
miner::find_nonce_for_given_block(b, template_res.difficulty, template_res.height); miner::find_nonce_for_given_block(&(m_core.get_blockchain_storage()), b, template_res.difficulty, template_res.height);
submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b)); submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b));
r = on_submitblock(submit_req, submit_res, error_resp, ctx); r = on_submitblock(submit_req, submit_res, error_resp, ctx);
@ -1439,7 +1452,7 @@ namespace cryptonote
response.reward = get_block_reward(blk); response.reward = get_block_reward(blk);
response.block_size = response.block_weight = m_core.get_blockchain_storage().get_db().get_block_weight(height); response.block_size = response.block_weight = m_core.get_blockchain_storage().get_db().get_block_weight(height);
response.num_txes = blk.tx_hashes.size(); response.num_txes = blk.tx_hashes.size();
response.pow_hash = fill_pow_hash ? string_tools::pod_to_hex(get_block_longhash(blk, height)) : ""; response.pow_hash = fill_pow_hash ? string_tools::pod_to_hex(get_block_longhash(&(m_core.get_blockchain_storage()), blk, height, 0)) : "";
response.long_term_weight = m_core.get_blockchain_storage().get_db().get_block_long_term_weight(height); response.long_term_weight = m_core.get_blockchain_storage().get_db().get_block_long_term_weight(height);
response.miner_tx_hash = string_tools::pod_to_hex(cryptonote::get_transaction_hash(blk.miner_tx)); response.miner_tx_hash = string_tools::pod_to_hex(cryptonote::get_transaction_hash(blk.miner_tx));
return true; return true;

@ -84,7 +84,7 @@ namespace cryptonote
// advance which version they will stop working with // advance which version they will stop working with
// Don't go over 32767 for any of these // Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 2 #define CORE_RPC_VERSION_MAJOR 2
#define CORE_RPC_VERSION_MINOR 6 #define CORE_RPC_VERSION_MINOR 7
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@ -937,6 +937,8 @@ namespace cryptonote
uint64_t reserved_offset; uint64_t reserved_offset;
uint64_t expected_reward; uint64_t expected_reward;
std::string prev_hash; std::string prev_hash;
std::string seed_hash;
std::string next_seed_hash;
blobdata blocktemplate_blob; blobdata blocktemplate_blob;
blobdata blockhashing_blob; blobdata blockhashing_blob;
std::string status; std::string status;
@ -954,6 +956,8 @@ namespace cryptonote
KV_SERIALIZE(blockhashing_blob) KV_SERIALIZE(blockhashing_blob)
KV_SERIALIZE(status) KV_SERIALIZE(status)
KV_SERIALIZE(untrusted) KV_SERIALIZE(untrusted)
KV_SERIALIZE(seed_hash)
KV_SERIALIZE(next_seed_hash)
END_KV_SERIALIZE_MAP() END_KV_SERIALIZE_MAP()
}; };
typedef epee::misc_utils::struct_init<response_t> response; typedef epee::misc_utils::struct_init<response_t> response;

@ -209,7 +209,7 @@ bool tests::proxy_core::handle_incoming_block(const cryptonote::blobdata& block_
crypto::hash lh; crypto::hash lh;
cout << "BLOCK" << endl << endl; cout << "BLOCK" << endl << endl;
cout << (h = get_block_hash(b)) << endl; cout << (h = get_block_hash(b)) << endl;
cout << (lh = get_block_longhash(b, 0)) << endl; cout << (lh = get_block_longhash(NULL, b, 0, 0)) << endl;
cout << get_transaction_hash(b.miner_tx) << endl; cout << get_transaction_hash(b.miner_tx) << endl;
cout << ::get_object_blobsize(b.miner_tx) << endl; cout << ::get_object_blobsize(b.miner_tx) << endl;
//cout << string_tools::buff_to_hex_nodelimer(block_blob) << endl; //cout << string_tools::buff_to_hex_nodelimer(block_blob) << endl;
@ -236,7 +236,7 @@ void tests::proxy_core::get_blockchain_top(uint64_t& height, crypto::hash& top_i
bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/) { bool tests::proxy_core::init(const boost::program_options::variables_map& /*vm*/) {
generate_genesis_block(m_genesis, config::GENESIS_TX, config::GENESIS_NONCE); generate_genesis_block(m_genesis, config::GENESIS_TX, config::GENESIS_NONCE);
crypto::hash h = get_block_hash(m_genesis); crypto::hash h = get_block_hash(m_genesis);
add_block(h, get_block_longhash(m_genesis, 0), m_genesis, block_to_blob(m_genesis)); add_block(h, get_block_longhash(NULL, m_genesis, 0, 0), m_genesis, block_to_blob(m_genesis));
return true; return true;
} }

@ -186,7 +186,7 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co
// Nonce search... // Nonce search...
blk.nonce = 0; blk.nonce = 0;
while (!miner::find_nonce_for_given_block(blk, get_test_difficulty(hf_ver), height)) while (!miner::find_nonce_for_given_block(NULL, blk, get_test_difficulty(hf_ver), height))
blk.timestamp++; blk.timestamp++;
add_block(blk, txs_weight, block_weights, already_generated_coins, hf_ver ? hf_ver.get() : 1); add_block(blk, txs_weight, block_weights, already_generated_coins, hf_ver ? hf_ver.get() : 1);
@ -796,7 +796,7 @@ void fill_tx_sources_and_destinations(const std::vector<test_event_entry>& event
void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height) void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height)
{ {
blk.nonce = 0; blk.nonce = 0;
while (!miner::find_nonce_for_given_block(blk, diffic, height)) while (!miner::find_nonce_for_given_block(NULL, blk, diffic, height))
blk.timestamp++; blk.timestamp++;
} }

Loading…
Cancel
Save