mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Merge commit '13d73d9' into LokiMergeUpstream
This commit is contained in:
commit
97b4ed900b
|
@ -796,6 +796,7 @@ endif()
|
||||||
|
|
||||||
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
include_directories(SYSTEM ${Boost_INCLUDE_DIRS})
|
||||||
if(MINGW)
|
if(MINGW)
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
|
||||||
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi)
|
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi)
|
||||||
set(ICU_LIBRARIES ${Boost_LOCALE_LIBRARY} icuio icuin icuuc icudt icutu iconv)
|
set(ICU_LIBRARIES ${Boost_LOCALE_LIBRARY} icuio icuin icuuc icudt icutu iconv)
|
||||||
elseif(APPLE OR OPENBSD OR ANDROID)
|
elseif(APPLE OR OPENBSD OR ANDROID)
|
||||||
|
|
8
Makefile
8
Makefile
|
@ -49,6 +49,14 @@ debug-static-all:
|
||||||
mkdir -p build/debug
|
mkdir -p build/debug
|
||||||
cd build/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
cd build/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE)
|
||||||
|
|
||||||
|
debug-static-win64:
|
||||||
|
mkdir -p build/debug
|
||||||
|
cd build/debug && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE)
|
||||||
|
|
||||||
|
debug-static-win32:
|
||||||
|
mkdir -p build/debug
|
||||||
|
cd build/debug && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=Debug -D BUILD_TAG="win-x32" -D CMAKE_TOOLCHAIN_FILE=../../cmake/32-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys32 ../.. && $(MAKE)
|
||||||
|
|
||||||
cmake-release:
|
cmake-release:
|
||||||
mkdir -p build/release
|
mkdir -p build/release
|
||||||
cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../..
|
cd build/release && cmake -D CMAKE_BUILD_TYPE=Release ../..
|
||||||
|
|
10
README.md
10
README.md
|
@ -238,6 +238,16 @@ application.
|
||||||
|
|
||||||
* The resulting executables can be found in `build/release/bin`
|
* The resulting executables can be found in `build/release/bin`
|
||||||
|
|
||||||
|
* **Optional**: to build Windows binaries suitable for debugging on a 64-bit system, run:
|
||||||
|
|
||||||
|
make debug-static-win64
|
||||||
|
|
||||||
|
* **Optional**: to build Windows binaries suitable for debugging on a 32-bit system, run:
|
||||||
|
|
||||||
|
make debug-static-win32
|
||||||
|
|
||||||
|
* The resulting executables can be found in `build/debug/bin`
|
||||||
|
|
||||||
### On FreeBSD:
|
### On FreeBSD:
|
||||||
|
|
||||||
The project can be built from scratch by following instructions for Linux above. If you are running loki in a jail you need to add the flag: `allow.sysvipc=1` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
|
The project can be built from scratch by following instructions for Linux above. If you are running loki in a jail you need to add the flag: `allow.sysvipc=1` to your jail configuration, otherwise lmdb will throw the error message: `Failed to open lmdb environment: Function not implemented`.
|
||||||
|
|
|
@ -834,6 +834,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
uint8_t get_hard_fork_version(uint64_t height) const { return m_hardfork->get(height); }
|
uint8_t get_hard_fork_version(uint64_t height) const { return m_hardfork->get(height); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief returns the earliest block a given version may activate
|
||||||
|
*
|
||||||
|
* @return the height
|
||||||
|
*/
|
||||||
|
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return m_hardfork->get_earliest_ideal_height_for_version(version); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief get information about hardfork voting for a version
|
* @brief get information about hardfork voting for a version
|
||||||
*
|
*
|
||||||
|
|
|
@ -1515,6 +1515,11 @@ namespace cryptonote
|
||||||
return get_blockchain_storage().get_hard_fork_version(height);
|
return get_blockchain_storage().get_hard_fork_version(height);
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
uint64_t core::get_earliest_ideal_height_for_version(uint8_t version) const
|
||||||
|
{
|
||||||
|
return get_blockchain_storage().get_earliest_ideal_height_for_version(version);
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
bool core::check_updates()
|
bool core::check_updates()
|
||||||
{
|
{
|
||||||
static const char software[] = "loki";
|
static const char software[] = "loki";
|
||||||
|
|
|
@ -678,6 +678,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
uint8_t get_hard_fork_version(uint64_t height) const;
|
uint8_t get_hard_fork_version(uint64_t height) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief return the earliest block a given version may activate
|
||||||
|
*
|
||||||
|
* @return what it says above
|
||||||
|
*/
|
||||||
|
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief gets start_time
|
* @brief gets start_time
|
||||||
*
|
*
|
||||||
|
|
|
@ -779,6 +779,16 @@ std::string WalletImpl::publicSpendKey() const
|
||||||
return epee::string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key);
|
return epee::string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_account_address.m_spend_public_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string WalletImpl::publicMultisigSignerKey() const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
crypto::public_key signer = m_wallet->get_multisig_signer_public_key();
|
||||||
|
return epee::string_tools::pod_to_hex(signer);
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string WalletImpl::path() const
|
std::string WalletImpl::path() const
|
||||||
{
|
{
|
||||||
return m_wallet->path();
|
return m_wallet->path();
|
||||||
|
@ -1767,6 +1777,50 @@ bool WalletImpl::verifySignedMessage(const std::string &message, const std::stri
|
||||||
return m_wallet->verify(message, info.address, signature);
|
return m_wallet->verify(message, info.address, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string WalletImpl::signMultisigParticipant(const std::string &message) const
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
|
||||||
|
bool ready = false;
|
||||||
|
if (!m_wallet->multisig(&ready) || !ready) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = tr("The wallet must be in multisig ready state");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return m_wallet->sign_multisig_participant(message);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
|
||||||
|
cryptonote::blobdata pkeyData;
|
||||||
|
if(!epee::string_tools::parse_hexstr_to_binbuff(publicKey, pkeyData) || pkeyData.size() != sizeof(crypto::public_key))
|
||||||
|
{
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = tr("Given string is not a key");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
crypto::public_key pkey = *reinterpret_cast<const crypto::public_key*>(pkeyData.data());
|
||||||
|
return m_wallet->verify_with_public_key(message, pkey, signature);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = e.what();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool WalletImpl::connectToDaemon()
|
bool WalletImpl::connectToDaemon()
|
||||||
{
|
{
|
||||||
bool result = m_wallet->check_connection(NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
bool result = m_wallet->check_connection(NULL, DEFAULT_CONNECTION_TIMEOUT_MILLIS);
|
||||||
|
|
|
@ -91,6 +91,7 @@ public:
|
||||||
std::string publicViewKey() const;
|
std::string publicViewKey() const;
|
||||||
std::string secretSpendKey() const;
|
std::string secretSpendKey() const;
|
||||||
std::string publicSpendKey() const;
|
std::string publicSpendKey() const;
|
||||||
|
std::string publicMultisigSignerKey() const;
|
||||||
std::string path() const;
|
std::string path() const;
|
||||||
bool store(const std::string &path);
|
bool store(const std::string &path);
|
||||||
std::string filename() const;
|
std::string filename() const;
|
||||||
|
@ -166,6 +167,8 @@ public:
|
||||||
virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const;
|
virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent) const;
|
||||||
virtual std::string signMessage(const std::string &message);
|
virtual std::string signMessage(const std::string &message);
|
||||||
virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const;
|
virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const;
|
||||||
|
virtual std::string signMultisigParticipant(const std::string &message) const;
|
||||||
|
virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const;
|
||||||
virtual void startRefresh();
|
virtual void startRefresh();
|
||||||
virtual void pauseRefresh();
|
virtual void pauseRefresh();
|
||||||
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
|
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error);
|
||||||
|
|
|
@ -443,6 +443,12 @@ struct Wallet
|
||||||
*/
|
*/
|
||||||
virtual std::string publicSpendKey() const = 0;
|
virtual std::string publicSpendKey() const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief publicMultisigSignerKey - returns public signer key
|
||||||
|
* \return - public multisignature signer key or empty string if wallet is not multisig
|
||||||
|
*/
|
||||||
|
virtual std::string publicMultisigSignerKey() const = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief store - stores wallet to file.
|
* \brief store - stores wallet to file.
|
||||||
* \param path - main filename to store wallet to. additionally stores address file and keys file.
|
* \param path - main filename to store wallet to. additionally stores address file and keys file.
|
||||||
|
@ -825,6 +831,21 @@ struct Wallet
|
||||||
*/
|
*/
|
||||||
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
virtual bool verifySignedMessage(const std::string &message, const std::string &addres, const std::string &signature) const = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief signMultisigParticipant signs given message with the multisig public signer key
|
||||||
|
* \param message message to sign
|
||||||
|
* \return signature in case of success. Sets status to Error and return empty string in case of error
|
||||||
|
*/
|
||||||
|
virtual std::string signMultisigParticipant(const std::string &message) const = 0;
|
||||||
|
/*!
|
||||||
|
* \brief verifyMessageWithPublicKey verifies that message was signed with the given public key
|
||||||
|
* \param message message
|
||||||
|
* \param publicKey hex encoded public key
|
||||||
|
* \param signature signature of the message
|
||||||
|
* \return true if the signature is correct. false and sets error state in case of error
|
||||||
|
*/
|
||||||
|
virtual bool verifyMessageWithPublicKey(const std::string &message, const std::string &publicKey, const std::string &signature) const = 0;
|
||||||
|
|
||||||
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
|
virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &amount, std::string &tx_description, std::string &recipient_name, std::vector<std::string> &unknown_parameters, std::string &error) = 0;
|
||||||
|
|
||||||
virtual std::string getDefaultDataDir() const = 0;
|
virtual std::string getDefaultDataDir() const = 0;
|
||||||
|
|
|
@ -114,6 +114,8 @@ using namespace cryptonote;
|
||||||
#define STAGENET_SEGREGATION_FORK_HEIGHT 1000000
|
#define STAGENET_SEGREGATION_FORK_HEIGHT 1000000
|
||||||
#define SEGREGATION_FORK_VICINITY 1500 /* blocks */
|
#define SEGREGATION_FORK_VICINITY 1500 /* blocks */
|
||||||
|
|
||||||
|
static const std::string MULTISIG_SIGNATURE_MAGIC = "SigMultisigPkV1";
|
||||||
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -9278,6 +9280,40 @@ bool wallet2::verify(const std::string &data, const cryptonote::account_public_a
|
||||||
memcpy(&s, decoded.data(), sizeof(s));
|
memcpy(&s, decoded.data(), sizeof(s));
|
||||||
return crypto::check_signature(hash, address.m_spend_public_key, s);
|
return crypto::check_signature(hash, address.m_spend_public_key, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string wallet2::sign_multisig_participant(const std::string& data) const
|
||||||
|
{
|
||||||
|
CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig");
|
||||||
|
|
||||||
|
crypto::hash hash;
|
||||||
|
crypto::cn_fast_hash(data.data(), data.size(), hash);
|
||||||
|
const cryptonote::account_keys &keys = m_account.get_keys();
|
||||||
|
crypto::signature signature;
|
||||||
|
crypto::generate_signature(hash, get_multisig_signer_public_key(), keys.m_spend_secret_key, signature);
|
||||||
|
return MULTISIG_SIGNATURE_MAGIC + tools::base58::encode(std::string((const char *)&signature, sizeof(signature)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wallet2::verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const
|
||||||
|
{
|
||||||
|
if (signature.size() < MULTISIG_SIGNATURE_MAGIC.size() || signature.substr(0, MULTISIG_SIGNATURE_MAGIC.size()) != MULTISIG_SIGNATURE_MAGIC) {
|
||||||
|
MERROR("Signature header check error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crypto::hash hash;
|
||||||
|
crypto::cn_fast_hash(data.data(), data.size(), hash);
|
||||||
|
std::string decoded;
|
||||||
|
if (!tools::base58::decode(signature.substr(MULTISIG_SIGNATURE_MAGIC.size()), decoded)) {
|
||||||
|
MERROR("Signature decoding error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
crypto::signature s;
|
||||||
|
if (sizeof(s) != decoded.size()) {
|
||||||
|
MERROR("Signature decoding error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(&s, decoded.data(), sizeof(s));
|
||||||
|
return crypto::check_signature(hash, public_key, s);
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
|
crypto::public_key wallet2::get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const
|
||||||
{
|
{
|
||||||
|
|
|
@ -986,6 +986,22 @@ namespace tools
|
||||||
std::string sign(const std::string &data) const;
|
std::string sign(const std::string &data) const;
|
||||||
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
|
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief sign_multisig_participant signs given message with the multisig public signer key
|
||||||
|
* \param data message to sign
|
||||||
|
* \throws if wallet is not multisig
|
||||||
|
* \return signature
|
||||||
|
*/
|
||||||
|
std::string sign_multisig_participant(const std::string& data) const;
|
||||||
|
/*!
|
||||||
|
* \brief verify_with_public_key verifies message was signed with given public key
|
||||||
|
* \param data message
|
||||||
|
* \param public_key public key to check signature
|
||||||
|
* \param signature signature of the message
|
||||||
|
* \return true if the signature is correct
|
||||||
|
*/
|
||||||
|
bool verify_with_public_key(const std::string &data, const crypto::public_key &public_key, const std::string &signature) const;
|
||||||
|
|
||||||
// Import/Export wallet data
|
// Import/Export wallet data
|
||||||
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
||||||
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
||||||
|
|
|
@ -102,6 +102,7 @@ namespace tests
|
||||||
uint8_t get_ideal_hard_fork_version() const { return 0; }
|
uint8_t get_ideal_hard_fork_version() const { return 0; }
|
||||||
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
|
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
|
||||||
uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
|
uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
|
||||||
|
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return 0; }
|
||||||
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
|
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
|
||||||
bool fluffy_blocks_enabled() const { return false; }
|
bool fluffy_blocks_enabled() const { return false; }
|
||||||
uint64_t prevalidate_block_hashes(uint64_t height, const std::list<crypto::hash> &hashes) { return 0; }
|
uint64_t prevalidate_block_hashes(uint64_t height, const std::list<crypto::hash> &hashes) { return 0; }
|
||||||
|
|
|
@ -46,7 +46,7 @@ endmacro()
|
||||||
# Google Mock. You can tweak these definitions to suit your need. A
|
# Google Mock. You can tweak these definitions to suit your need. A
|
||||||
# variable's value is empty before it's explicitly assigned to.
|
# variable's value is empty before it's explicitly assigned to.
|
||||||
macro(config_compiler_and_linker)
|
macro(config_compiler_and_linker)
|
||||||
if (NOT gtest_disable_pthreads)
|
if (NOT gtest_disable_pthreads AND NOT MINGW)
|
||||||
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
||||||
find_package(Threads)
|
find_package(Threads)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -1553,10 +1553,7 @@ class GTEST_API_ Notification {
|
||||||
};
|
};
|
||||||
# endif // GTEST_HAS_NOTIFICATION_
|
# endif // GTEST_HAS_NOTIFICATION_
|
||||||
|
|
||||||
// On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD
|
# if GTEST_HAS_PTHREAD
|
||||||
// defined, but we don't want to use MinGW's pthreads implementation, which
|
|
||||||
// has conformance problems with some versions of the POSIX standard.
|
|
||||||
# if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW
|
|
||||||
|
|
||||||
// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
|
// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
|
||||||
// Consequently, it cannot select a correct instantiation of ThreadWithParam
|
// Consequently, it cannot select a correct instantiation of ThreadWithParam
|
||||||
|
|
|
@ -80,6 +80,7 @@ public:
|
||||||
uint8_t get_ideal_hard_fork_version() const { return 0; }
|
uint8_t get_ideal_hard_fork_version() const { return 0; }
|
||||||
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
|
uint8_t get_ideal_hard_fork_version(uint64_t height) const { return 0; }
|
||||||
uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
|
uint8_t get_hard_fork_version(uint64_t height) const { return 0; }
|
||||||
|
uint64_t get_earliest_ideal_height_for_version(uint8_t version) const { return 0; }
|
||||||
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
|
cryptonote::difficulty_type get_block_cumulative_difficulty(uint64_t height) const { return 0; }
|
||||||
bool fluffy_blocks_enabled() const { return false; }
|
bool fluffy_blocks_enabled() const { return false; }
|
||||||
uint64_t prevalidate_block_hashes(uint64_t height, const std::list<crypto::hash> &hashes) { return 0; }
|
uint64_t prevalidate_block_hashes(uint64_t height, const std::list<crypto::hash> &hashes) { return 0; }
|
||||||
|
|
Loading…
Reference in a new issue