Merge commit '8f9c381' into LokiMergeUpstream

This commit is contained in:
doy-lee 2018-10-31 17:26:00 +11:00
commit 997c0a9991
27 changed files with 414 additions and 198 deletions

View File

@ -204,6 +204,9 @@ set(PER_BLOCK_CHECKPOINT 1)
if(PER_BLOCK_CHECKPOINT)
add_definitions("-DPER_BLOCK_CHECKPOINT")
set(Blocks "blocks")
else()
set(Blocks "")
endif()
list(INSERT CMAKE_MODULE_PATH 0
@ -679,12 +682,10 @@ else()
add_linker_flag_if_supported(-Wl,-z,noexecstack noexecstack_SUPPORTED)
if (noexecstack_SUPPORTED)
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecstack")
set(LD_RAW_FLAGS ${LD_RAW_FLAGS} -z noexecstack)
endif()
add_linker_flag_if_supported(-Wl,-z,noexecheap noexecheap_SUPPORTED)
if (noexecheap_SUPPORTED)
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
set(LD_RAW_FLAGS ${LD_RAW_FLAGS} -z noexecheap)
endif()
# some windows linker bits

View File

@ -147,6 +147,8 @@ Tested on a Raspberry Pi Zero with a clean install of minimal Raspbian Stretch (
CONF_SWAPSIZE=1024
sudo /etc/init.d/dphys-swapfile start
```
* If using an external hard disk without an external power supply, ensure it gets enough power to avoid hardware issues when syncing, by adding the line "max_usb_current=1" to /boot/config.txt
* Clone loki and checkout most recent release version:
```
git clone https://github.com/loki-project/loki.git

View File

@ -27,6 +27,7 @@ namespace rdln
private:
std::streambuf* m_cout_buf;
size_t m_prompt_length;
static std::vector<std::string>& completion_commands();
};

View File

@ -44,7 +44,7 @@ std::vector<std::string>& rdln::readline_buffer::completion_commands()
}
rdln::readline_buffer::readline_buffer()
: std::stringbuf(), m_cout_buf(NULL)
: std::stringbuf(), m_cout_buf(NULL), m_prompt_length(0)
{
current = this;
}
@ -86,8 +86,11 @@ void rdln::readline_buffer::set_prompt(const std::string& prompt)
if(m_cout_buf == NULL)
return;
boost::lock_guard<boost::mutex> lock(sync_mutex);
rl_set_prompt(std::string(m_prompt_length, ' ').c_str());
rl_redisplay();
rl_set_prompt(prompt.c_str());
rl_redisplay();
m_prompt_length = prompt.size();
}
void rdln::readline_buffer::add_completion(const std::string& command)

View File

@ -27,20 +27,6 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set(blocksdat "")
if(PER_BLOCK_CHECKPOINT)
if(APPLE AND DEPENDS)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} --target=x86_64-apple-darwin11 -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
elseif(APPLE AND NOT DEPENDS)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
elseif(LINUX_32)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
else()
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
endif()
set(blocksdat "blocksdat.o")
endif()
set(blockchain_import_sources
blockchain_import.cpp
bootstrap_file.cpp
@ -118,8 +104,7 @@ loki_private_headers(blockchain_depth
loki_add_executable(blockchain_import
${blockchain_import_sources}
${blockchain_import_private_headers}
${blocksdat})
${blockchain_import_private_headers})
target_link_libraries(blockchain_import
PRIVATE
@ -131,7 +116,8 @@ target_link_libraries(blockchain_import
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
${CMAKE_THREAD_LIBS_INIT}
${EXTRA_LIBRARIES})
${EXTRA_LIBRARIES}
${Blocks})
if(ARCH_WIDTH)
target_compile_definitions(blockchain_import

View File

@ -38,6 +38,7 @@
#include "misc_log_ex.h"
#include "bootstrap_file.h"
#include "bootstrap_serialization.h"
#include "blocks/blocks.h"
#include "cryptonote_basic/cryptonote_format_utils.h"
#include "serialization/binary_utils.h" // dump_binary(), parse_binary()
#include "serialization/json_utils.h" // dump_json()
@ -759,7 +760,12 @@ int main(int argc, char* argv[])
{
core.disable_dns_checkpoints(true);
if (!core.init(vm, NULL))
#if defined(PER_BLOCK_CHECKPOINT)
const GetCheckpointsCallback& get_checkpoints = blocks::GetCheckpointsData;
#else
const GetCheckpointsCallback& get_checkpoints = nullptr;
#endif
if (!core.init(vm, nullptr, nullptr, get_checkpoints))
{
std::cerr << "Failed to initialize core" << ENDL;
return 1;

View File

@ -26,20 +26,23 @@
# 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.
if(APPLE)
add_library(blocks STATIC blockexports.c)
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
else()
if(LINUX_32)
add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat)
else()
add_custom_command(OUTPUT blocks.o MAIN_DEPENDENCY blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat)
add_custom_command(OUTPUT testnet_blocks.o MAIN_DEPENDENCY testnet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/testnet_blocks.o testnet_blocks.dat)
add_custom_command(OUTPUT stagenet_blocks.o MAIN_DEPENDENCY stagenet_blocks.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/stagenet_blocks.o stagenet_blocks.dat)
endif()
add_library(blocks STATIC blocks.o testnet_blocks.o stagenet_blocks.o blockexports.c)
set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C)
endif()
set(GENERATED_SOURCES "")
foreach(BLOB_NAME checkpoints testnet_blocks stagenet_blocks)
set(OUTPUT_C_SOURCE "generated_${BLOB_NAME}.c")
list(APPEND GENERATED_SOURCES ${OUTPUT_C_SOURCE})
set(INPUT_DAT_FILE "${BLOB_NAME}.dat")
add_custom_command(
OUTPUT ${OUTPUT_C_SOURCE}
MAIN_DEPENDENCY ${INPUT_DAT_FILE}
COMMAND
cd ${CMAKE_CURRENT_BINARY_DIR} &&
echo "'#include\t<stddef.h>'" > ${OUTPUT_C_SOURCE} &&
echo "'const\tunsigned\tchar\t${BLOB_NAME}[]={'" >> ${OUTPUT_C_SOURCE} &&
od -v -An -tu1 ${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_DAT_FILE} | sed -e "'s/[0-9]\\{1,\\}/&,/g'" -e "'$$s/.$$//'" >> ${OUTPUT_C_SOURCE} &&
echo "'};'" >> ${OUTPUT_C_SOURCE} &&
echo "'const\tsize_t\t${BLOB_NAME}_len\t=\tsizeof(${BLOB_NAME});'" >> ${OUTPUT_C_SOURCE}
)
endforeach()
add_library(blocks STATIC blocks.cpp ${GENERATED_SOURCES})

View File

@ -1,87 +0,0 @@
#include <stddef.h>
#if defined(__APPLE__)
#include <mach-o/getsect.h>
#ifdef BUILD_SHARED_LIBS
#if !defined(__LP64__)
const struct mach_header _mh_execute_header;
#else
const struct mach_header_64 _mh_execute_header;
#endif
#else
#if !defined(__LP64__)
extern const struct mach_header _mh_execute_header;
#else
extern const struct mach_header_64 _mh_execute_header;
#endif
#endif
const unsigned char *get_blocks_dat_start(int testnet, int stagenet)
{
size_t size;
if (testnet)
return getsectiondata(&_mh_execute_header, "__DATA", "__testnet_blocks_dat", &size);
else if (stagenet)
return getsectiondata(&_mh_execute_header, "__DATA", "__stagenet_blocks_dat", &size);
else
return getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size);
}
size_t get_blocks_dat_size(int testnet, int stagenet)
{
size_t size;
if (testnet)
getsectiondata(&_mh_execute_header, "__DATA", "__testnet_blocks_dat", &size);
else if (stagenet)
getsectiondata(&_mh_execute_header, "__DATA", "__stagenet_blocks_dat", &size);
else
getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size);
return size;
}
#else
#if defined(_WIN32) && !defined(_WIN64)
#define _binary_blocks_start binary_blocks_dat_start
#define _binary_blocks_end binary_blocks_dat_end
#define _binary_testnet_blocks_start binary_testnet_blocks_dat_start
#define _binary_testnet_blocks_end binary_testnet_blocks_dat_end
#define _binary_stagenet_blocks_start binary_stagenet_blocks_dat_start
#define _binary_stagenet_blocks_end binary_stagenet_blocks_dat_end
#else
#define _binary_blocks_start _binary_blocks_dat_start
#define _binary_blocks_end _binary_blocks_dat_end
#define _binary_testnet_blocks_start _binary_testnet_blocks_dat_start
#define _binary_testnet_blocks_end _binary_testnet_blocks_dat_end
#define _binary_stagenet_blocks_start _binary_stagenet_blocks_dat_start
#define _binary_stagenet_blocks_end _binary_stagenet_blocks_dat_end
#endif
extern const unsigned char _binary_blocks_start[];
extern const unsigned char _binary_blocks_end[];
extern const unsigned char _binary_testnet_blocks_start[];
extern const unsigned char _binary_testnet_blocks_end[];
extern const unsigned char _binary_stagenet_blocks_start[];
extern const unsigned char _binary_stagenet_blocks_end[];
const unsigned char *get_blocks_dat_start(int testnet, int stagenet)
{
if (testnet)
return _binary_testnet_blocks_start;
else if (stagenet)
return _binary_stagenet_blocks_start;
else
return _binary_blocks_start;
}
size_t get_blocks_dat_size(int testnet, int stagenet)
{
if (testnet)
return (size_t) (_binary_testnet_blocks_end - _binary_testnet_blocks_start);
else if (stagenet)
return (size_t) (_binary_stagenet_blocks_end - _binary_stagenet_blocks_start);
else
return (size_t) (_binary_blocks_end - _binary_blocks_start);
}
#endif

31
src/blocks/blocks.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "blocks.h"
#include <unordered_map>
extern const unsigned char checkpoints[];
extern const size_t checkpoints_len;
extern const unsigned char stagenet_blocks[];
extern const size_t stagenet_blocks_len;
extern const unsigned char testnet_blocks[];
extern const size_t testnet_blocks_len;
namespace blocks
{
const std::unordered_map<cryptonote::network_type, const epee::span<const unsigned char>, std::hash<size_t>> CheckpointsByNetwork = {
{cryptonote::network_type::MAINNET, {checkpoints, checkpoints_len}},
{cryptonote::network_type::STAGENET, {stagenet_blocks, stagenet_blocks_len}},
{cryptonote::network_type::TESTNET, {testnet_blocks, testnet_blocks_len}}
};
const epee::span<const unsigned char> GetCheckpointsData(cryptonote::network_type network)
{
const auto it = CheckpointsByNetwork.find(network);
if (it != CheckpointsByNetwork.end())
{
return it->second;
}
return nullptr;
}
}

View File

View File

@ -1,16 +1,12 @@
#ifndef SRC_BLOCKS_BLOCKS_H_
#define SRC_BLOCKS_BLOCKS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "cryptonote_config.h"
#include "span.h"
const unsigned char *get_blocks_dat_start(int testnet, int stagenet);
size_t get_blocks_dat_size(int testnet, int stagenet);
#ifdef __cplusplus
namespace blocks
{
const epee::span<const unsigned char> GetCheckpointsData(cryptonote::network_type network);
}
#endif
#endif /* SRC_BLOCKS_BLOCKS_H_ */

View File

@ -309,10 +309,19 @@ namespace tools
StringCchCopy(pszOS, BUFSIZE, TEXT("Microsoft "));
// Test for the specific product.
if ( osvi.dwMajorVersion == 10 )
{
if ( osvi.dwMinorVersion == 0 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 10 "));
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2016 " ));
}
}
if ( osvi.dwMajorVersion == 6 )
{
if( osvi.dwMinorVersion == 0 )
if ( osvi.dwMinorVersion == 0 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows Vista "));
@ -326,6 +335,20 @@ namespace tools
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2008 R2 " ));
}
if ( osvi.dwMinorVersion == 2 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8 "));
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 " ));
}
if ( osvi.dwMinorVersion == 3 )
{
if( osvi.wProductType == VER_NT_WORKSTATION )
StringCchCat(pszOS, BUFSIZE, TEXT("Windows 8.1 "));
else StringCchCat(pszOS, BUFSIZE, TEXT("Windows Server 2012 R2 " ));
}
pGPI = (PGPI) GetProcAddress(
GetModuleHandle(TEXT("kernel32.dll")),
"GetProductInfo");

View File

@ -30,6 +30,7 @@
#pragma once
#include <stdexcept>
#include <string>
#include <boost/uuid/uuid.hpp>
#include <stdexcept>

View File

@ -48,12 +48,6 @@ set(cryptonote_core_private_headers
tx_pool.h
cryptonote_tx_utils.h)
if(PER_BLOCK_CHECKPOINT)
set(Blocks "blocks")
else()
set(Blocks "")
endif()
loki_private_headers(cryptonote_core
${cryptonote_core_private_headers})
loki_add_library(cryptonote_core
@ -76,5 +70,4 @@ target_link_libraries(cryptonote_core
${Boost_SYSTEM_LIBRARY}
${Boost_THREAD_LIBRARY}
PRIVATE
${Blocks}
${EXTRA_LIBRARIES})

View File

@ -56,9 +56,6 @@
#include "ringct/rctSigs.h"
#include "common/perf_timer.h"
#include "common/notify.h"
#if defined(PER_BLOCK_CHECKPOINT)
#include "blocks/blocks.h"
#endif
#include "service_node_deregister.h"
#include "service_node_list.h"
@ -303,7 +300,7 @@ uint64_t Blockchain::get_current_blockchain_height() const
//------------------------------------------------------------------
//FIXME: possibly move this into the constructor, to avoid accidentally
// dereferencing a null BlockchainDB pointer
bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty)
bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty, const GetCheckpointsCallback& get_checkpoints/* = nullptr*/)
{
LOG_PRINT_L3("Blockchain::" << __func__);
@ -406,7 +403,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline
#if defined(PER_BLOCK_CHECKPOINT)
if (m_nettype != FAKECHAIN)
load_compiled_in_block_hashes();
load_compiled_in_block_hashes(get_checkpoints);
#endif
MINFO("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block());
@ -4546,19 +4543,21 @@ void Blockchain::cancel()
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "63b6445540c13f74d73fd753906e80bb84328c57b5a5a90c73353ed8405e7043";
void Blockchain::load_compiled_in_block_hashes()
void Blockchain::load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints)
{
const bool testnet = m_nettype == TESTNET;
const bool stagenet = m_nettype == STAGENET;
if (m_fast_sync && get_blocks_dat_start(testnet, stagenet) != nullptr && get_blocks_dat_size(testnet, stagenet) > 0)
if (get_checkpoints == nullptr || !m_fast_sync)
{
MINFO("Loading precomputed blocks (" << get_blocks_dat_size(testnet, stagenet) << " bytes)");
return;
}
const epee::span<const unsigned char> &checkpoints = get_checkpoints(m_nettype);
if (!checkpoints.empty())
{
MINFO("Loading precomputed blocks (" << checkpoints.size() << " bytes)");
if (m_nettype == MAINNET)
{
// first check hash
crypto::hash hash;
if (!tools::sha256sum(get_blocks_dat_start(testnet, stagenet), get_blocks_dat_size(testnet, stagenet), hash))
if (!tools::sha256sum(checkpoints.data(), checkpoints.size(), hash))
{
MERROR("Failed to hash precomputed blocks data");
return;
@ -4578,9 +4577,9 @@ void Blockchain::load_compiled_in_block_hashes()
}
}
if (get_blocks_dat_size(testnet, stagenet) > 4)
if (checkpoints.size() > 4)
{
const unsigned char *p = get_blocks_dat_start(testnet, stagenet);
const unsigned char *p = checkpoints.data();
const uint32_t nblocks = *p | ((*(p+1))<<8) | ((*(p+2))<<16) | ((*(p+3))<<24);
if (nblocks > (std::numeric_limits<uint32_t>::max() - 4) / sizeof(hash))
{
@ -4588,7 +4587,7 @@ void Blockchain::load_compiled_in_block_hashes()
return;
}
const size_t size_needed = 4 + nblocks * sizeof(crypto::hash);
if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && get_blocks_dat_size(testnet, stagenet) >= size_needed)
if(nblocks > 0 && nblocks > (m_db->height() + HASH_OF_HASHES_STEP - 1) / HASH_OF_HASHES_STEP && checkpoints.size() >= size_needed)
{
p += sizeof(uint32_t);
m_blocks_hash_of_hashes.reserve(nblocks);

View File

@ -38,9 +38,11 @@
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>
#include <atomic>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include "span.h"
#include "syncobj.h"
#include "string_tools.h"
#include "cryptonote_basic/cryptonote_basic.h"
@ -75,6 +77,15 @@ namespace cryptonote
db_nosync //!< Leave syncing up to the backing db (safest, but slowest because of disk I/O)
};
/**
* @brief Callback routine that returns checkpoints data for specific network type
*
* @param network network type
*
* @return checkpoints data, empty span if there ain't any checkpoints for specific network type
*/
typedef std::function<const epee::span<const unsigned char>(cryptonote::network_type network)> GetCheckpointsCallback;
/************************************************************************/
/* */
/************************************************************************/
@ -151,10 +162,11 @@ namespace cryptonote
* @param offline true if running offline, else false
* @param test_options test parameters
* @param fixed_difficulty fixed difficulty for testing purposes; 0 means disabled
* @param get_checkpoints if set, will be called to get checkpoints data
*
* @return true on success, false if any initialization steps fail
*/
bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0);
bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0, const GetCheckpointsCallback& get_checkpoints = nullptr);
/**
* @brief Initialize the Blockchain state
@ -1426,8 +1438,10 @@ namespace cryptonote
* A (possibly empty) set of block hashes can be compiled into the
* monero daemon binary. This function loads those hashes into
* a useful state.
*
* @param get_checkpoints if set, will be called to get checkpoints data
*/
void load_compiled_in_block_hashes();
void load_compiled_in_block_hashes(const GetCheckpointsCallback& get_checkpoints);
/**
* @brief expands v2 transaction data from blockchain

View File

@ -404,7 +404,7 @@ namespace cryptonote
return m_blockchain_storage.get_alternative_blocks_count();
}
//-----------------------------------------------------------------------------------------------
bool core::init(const boost::program_options::variables_map& vm, const char *config_subdir, const cryptonote::test_options *test_options)
bool core::init(const boost::program_options::variables_map& vm, const char *config_subdir, const cryptonote::test_options *test_options, const GetCheckpointsCallback& get_checkpoints/* = nullptr */)
{
start_time = std::time(nullptr);
@ -593,7 +593,7 @@ namespace cryptonote
BlockchainDB *initialized_db = db.release();
m_service_node_list.set_db_pointer(initialized_db);
m_service_node_list.register_hooks(m_quorum_cop);
r = m_blockchain_storage.init(initialized_db, m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty);
r = m_blockchain_storage.init(initialized_db, m_nettype, m_offline, regtest ? &regtest_test_options : test_options, fixed_difficulty, get_checkpoints);
r = m_mempool.init(max_txpool_weight);
CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool");

View File

@ -260,10 +260,11 @@ namespace cryptonote
* @param vm command line parameters
* @param config_subdir subdirectory for config storage
* @param test_options configuration options for testing
* @param get_checkpoints if set, will be called to get checkpoints data, must return checkpoints data pointer and size or nullptr if there ain't any checkpoints for specific network type
*
* @return false if one of the init steps fails, otherwise true
*/
bool init(const boost::program_options::variables_map& vm, const char *config_subdir = NULL, const test_options *test_options = NULL);
bool init(const boost::program_options::variables_map& vm, const char *config_subdir = NULL, const test_options *test_options = NULL, const GetCheckpointsCallback& get_checkpoints = nullptr);
/**
* @copydoc Blockchain::reset_and_set_genesis_block

View File

@ -27,20 +27,6 @@
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set(blocksdat "")
if(PER_BLOCK_CHECKPOINT)
if(APPLE AND DEPENDS)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} --target=x86_64-apple-darwin11 -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
elseif(APPLE AND NOT DEPENDS)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*)
elseif(LINUX_32)
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} -m elf_i386 ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
else()
add_custom_command(OUTPUT blocksdat.o MAIN_DEPENDENCY ../blocks/checkpoints.dat COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ${CMAKE_LINKER} ${LD_RAW_FLAGS} -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat)
endif()
set(blocksdat "blocksdat.o")
endif()
set(daemon_sources
command_parser_executor.cpp
command_server.cpp
@ -82,9 +68,7 @@ loki_private_headers(daemon
loki_add_executable(daemon
${daemon_sources}
${daemon_headers}
${daemon_private_headers}
${blocksdat}
)
${daemon_private_headers})
target_link_libraries(daemon
PRIVATE
rpc
@ -107,7 +91,8 @@ target_link_libraries(daemon
${CMAKE_THREAD_LIBS_INIT}
${ZMQ_LIB}
${GNU_READLINE_LIBRARY}
${EXTRA_LIBRARIES})
${EXTRA_LIBRARIES}
${Blocks})
set_property(TARGET daemon
PROPERTY
OUTPUT_NAME "lokid")

View File

@ -29,6 +29,7 @@
#pragma once
#include "blocks/blocks.h"
#include "cryptonote_core/cryptonote_core.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
#include "misc_log_ex.h"
@ -86,7 +87,12 @@ public:
//initialize core here
MGINFO("Initializing core...");
std::string config_subdir = get_config_subdir();
if (!m_core.init(m_vm_HACK, config_subdir.empty() ? NULL : config_subdir.c_str()))
#if defined(PER_BLOCK_CHECKPOINT)
const cryptonote::GetCheckpointsCallback& get_checkpoints = blocks::GetCheckpointsData;
#else
const cryptonote::GetCheckpointsCallback& get_checkpoints = nullptr;
#endif
if (!m_core.init(m_vm_HACK, config_subdir.empty() ? NULL : config_subdir.c_str(), nullptr, get_checkpoints))
{
return false;
}

View File

@ -59,12 +59,6 @@ endif()
set(device_private_headers)
if(PER_BLOCK_CHECKPOINT)
set(Blocks "blocks")
else()
set(Blocks "")
endif()
loki_private_headers(device
${device_private_headers})
@ -80,5 +74,4 @@ target_link_libraries(device
ringct_basic
${OPENSSL_CRYPTO_LIBRARIES}
PRIVATE
${Blocks}
${EXTRA_LIBRARIES})

View File

@ -4726,8 +4726,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
if (!try_connect_to_daemon())
return true;
SCOPED_WALLET_UNLOCK();
std::vector<std::string> local_args = args_;
std::set<uint32_t> subaddr_indices;
@ -4905,6 +4903,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
}
SCOPED_WALLET_UNLOCK();
try
{
// figure out what tx will be necessary
@ -5523,6 +5523,13 @@ bool simple_wallet::register_service_node(const std::vector<std::string> &args_)
}
stop();
m_idle_run.store(false, std::memory_order_relaxed);
m_wallet->stop();
{
boost::unique_lock<boost::mutex> lock(m_idle_mutex);
m_idle_cond.notify_one();
}
m_idle_thread.join();
#ifndef WIN32
success_msg_writer(true /*color*/) << tr("Successfully entered autostaking mode, this wallet is moving into the background to automatically renew your service node every period.");
@ -6008,7 +6015,13 @@ bool simple_wallet::stake(const std::vector<std::string> &args_)
success_msg_writer(false/*color*/) << "\n";
}
stop();
m_idle_run.store(false, std::memory_order_relaxed);
m_wallet->stop();
{
boost::unique_lock<boost::mutex> lock(m_idle_mutex);
m_idle_cond.notify_one();
}
m_idle_thread.join();
#ifndef WIN32
success_msg_writer() << tr("Entering autostaking mode, forking to background...");
@ -8035,12 +8048,6 @@ bool simple_wallet::run()
void simple_wallet::stop()
{
m_cmd_binder.stop_handling();
m_idle_run.store(false, std::memory_order_relaxed);
m_wallet->stop();
// make the background refresh thread quit
boost::unique_lock<boost::mutex> lock(m_idle_mutex);
m_idle_cond.notify_one();
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector<std::string>()*/)

View File

@ -5652,6 +5652,10 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
ptx.construction_data = sd;
txs.push_back(ptx);
// add tx keys only to ptx
txs.back().tx_key = tx_key;
txs.back().additional_tx_keys = additional_tx_keys;
}
// add key images
@ -10595,7 +10599,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image));
THROW_WALLET_EXCEPTION_IF(!crypto::check_ring_signature((const crypto::hash&)key_image, key_image, pkeys, &signature),
error::wallet_internal_error, "Signature check failed: input " + boost::lexical_cast<std::string>(n) + "/"
error::signature_check_failed, boost::lexical_cast<std::string>(n) + "/"
+ boost::lexical_cast<std::string>(signed_key_images.size()) + ", key image " + epee::string_tools::pod_to_hex(key_image)
+ ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0]));

View File

@ -72,6 +72,7 @@ namespace tools
// tx_parse_error
// get_tx_pool_error
// out_of_hashchain_bounds_error
// signature_check_failed
// transfer_error *
// get_outs_general_error
// not_enough_unlocked_money
@ -422,6 +423,14 @@ namespace tools
std::string to_string() const { return refresh_error::to_string(); }
};
//----------------------------------------------------------------------------------------------------
struct signature_check_failed : public wallet_logic_error
{
explicit signature_check_failed(std::string&& loc, const std::string& message)
: wallet_logic_error(std::move(loc), "Signature check failed " + message)
{
}
};
//----------------------------------------------------------------------------------------------------
struct transfer_error : public wallet_logic_error
{
protected:

View File

@ -982,6 +982,8 @@ namespace tools
for (auto &ptx: ptxs)
{
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
if (req.get_tx_keys)
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
}
if (req.export_raw)
@ -995,6 +997,171 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_describe_transfer(const wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
if (m_restricted)
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
if (m_wallet->key_on_device())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "command not supported by HW wallet";
return false;
}
if(m_wallet->watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
er.message = "command not supported by watch-only wallet";
return false;
}
tools::wallet2::unsigned_tx_set exported_txs;
try
{
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
er.message = "Failed to parse hex.";
return false;
}
if(!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "cannot load unsigned_txset";
return false;
}
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "failed to parse unsigned transfers: " + std::string(e.what());
return false;
}
std::vector<tools::wallet2::pending_tx> ptx;
try
{
// gather info to ask the user
std::unordered_map<cryptonote::account_public_address, std::pair<std::string, uint64_t>> dests;
int first_known_non_zero_change_index = -1;
for (size_t n = 0; n < exported_txs.txes.size(); ++n)
{
const tools::wallet2::tx_construction_data &cd = exported_txs.txes[n];
res.desc.push_back({0, 0, std::numeric_limits<uint32_t>::max(), 0, {}, "", 0, "", 0, 0, ""});
wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::transfer_description &desc = res.desc.back();
std::vector<cryptonote::tx_extra_field> tx_extra_fields;
bool has_encrypted_payment_id = false;
crypto::hash8 payment_id8 = crypto::null_hash8;
if (cryptonote::parse_tx_extra(cd.extra, tx_extra_fields))
{
cryptonote::tx_extra_nonce extra_nonce;
if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce))
{
crypto::hash payment_id;
if(cryptonote::get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8))
{
desc.payment_id = epee::string_tools::pod_to_hex(payment_id8);
has_encrypted_payment_id = true;
}
else if (cryptonote::get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
{
desc.payment_id = epee::string_tools::pod_to_hex(payment_id);
}
}
}
for (size_t s = 0; s < cd.sources.size(); ++s)
{
desc.amount_in += cd.sources[s].amount;
size_t ring_size = cd.sources[s].outputs.size();
if (ring_size < desc.ring_size)
desc.ring_size = ring_size;
}
for (size_t d = 0; d < cd.splitted_dsts.size(); ++d)
{
const cryptonote::tx_destination_entry &entry = cd.splitted_dsts[d];
std::string address = cryptonote::get_account_address_as_str(m_wallet->nettype(), entry.is_subaddress, entry.addr);
if (has_encrypted_payment_id && !entry.is_subaddress)
address = cryptonote::get_account_integrated_address_as_str(m_wallet->nettype(), entry.addr, payment_id8);
auto i = dests.find(entry.addr);
if (i == dests.end())
dests.insert(std::make_pair(entry.addr, std::make_pair(address, entry.amount)));
else
i->second.second += entry.amount;
desc.amount_out += entry.amount;
}
if (cd.change_dts.amount > 0)
{
auto it = dests.find(cd.change_dts.addr);
if (it == dests.end())
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "Claimed change does not go to a paid address";
return false;
}
if (it->second.second < cd.change_dts.amount)
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "Claimed change is larger than payment to the change address";
return false;
}
if (cd.change_dts.amount > 0)
{
if (first_known_non_zero_change_index == -1)
first_known_non_zero_change_index = n;
const tools::wallet2::tx_construction_data &cdn = exported_txs.txes[first_known_non_zero_change_index];
if (memcmp(&cd.change_dts.addr, &cdn.change_dts.addr, sizeof(cd.change_dts.addr)))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "Change goes to more than one address";
return false;
}
}
desc.change_amount += cd.change_dts.amount;
it->second.second -= cd.change_dts.amount;
if (it->second.second == 0)
dests.erase(cd.change_dts.addr);
}
size_t n_dummy_outputs = 0;
for (auto i = dests.begin(); i != dests.end(); )
{
if (i->second.second > 0)
{
desc.recipients.push_back({i->second.first, i->second.second});
}
else
++desc.dummy_outputs;
++i;
}
if (desc.change_amount > 0)
{
const tools::wallet2::tx_construction_data &cd0 = exported_txs.txes[0];
desc.change_address = get_account_address_as_str(m_wallet->nettype(), cd0.subaddr_account > 0, cd0.change_dts.addr);
}
desc.fee = desc.amount_in - desc.amount_out;
desc.unlock_time = cd.unlock_time;
desc.extra = epee::to_hex::string({cd.extra.data(), cd.extra.size()});
}
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "failed to parse unsigned transfers";
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_submit_transfer(const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
@ -2906,6 +3073,11 @@ namespace tools
er.code = WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS;
er.message = e.what();
}
catch (const error::signature_check_failed& e)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE;
er.message = e.what();
}
catch (const std::exception& e)
{
er.code = default_error_code;

View File

@ -88,6 +88,7 @@ namespace tools
MAP_JON_RPC_WE("transfer", on_transfer, wallet_rpc::COMMAND_RPC_TRANSFER)
MAP_JON_RPC_WE("transfer_split", on_transfer_split, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT)
MAP_JON_RPC_WE("sign_transfer", on_sign_transfer, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER)
MAP_JON_RPC_WE("describe_transfer", on_describe_transfer, wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER)
MAP_JON_RPC_WE("submit_transfer", on_submit_transfer, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER)
MAP_JON_RPC_WE("sweep_dust", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST)
MAP_JON_RPC_WE("sweep_unmixable", on_sweep_dust, wallet_rpc::COMMAND_RPC_SWEEP_DUST)
@ -168,6 +169,7 @@ namespace tools
bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er);
bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er);
bool on_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er);
bool on_describe_transfer(const wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_DESCRIBE_TRANSFER::response& res, epee::json_rpc::error& er);
bool on_submit_transfer(const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er);
bool on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er);
bool on_sweep_all(const wallet_rpc::COMMAND_RPC_SWEEP_ALL::request& req, wallet_rpc::COMMAND_RPC_SWEEP_ALL::response& res, epee::json_rpc::error& er);

View File

@ -48,7 +48,7 @@
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
#define WALLET_RPC_VERSION_MINOR 4
#define WALLET_RPC_VERSION_MINOR 5
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
@ -532,16 +532,79 @@ namespace wallet_rpc
};
};
struct COMMAND_RPC_DESCRIBE_TRANSFER
{
struct recipient
{
std::string address;
uint64_t amount;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
KV_SERIALIZE(amount)
END_KV_SERIALIZE_MAP()
};
struct transfer_description
{
uint64_t amount_in;
uint64_t amount_out;
uint32_t ring_size;
uint64_t unlock_time;
std::list<recipient> recipients;
std::string payment_id;
uint64_t change_amount;
std::string change_address;
uint64_t fee;
uint32_t dummy_outputs;
std::string extra;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount_in)
KV_SERIALIZE(amount_out)
KV_SERIALIZE(ring_size)
KV_SERIALIZE(unlock_time)
KV_SERIALIZE(recipients)
KV_SERIALIZE(payment_id)
KV_SERIALIZE(change_amount)
KV_SERIALIZE(change_address)
KV_SERIALIZE(fee)
KV_SERIALIZE(dummy_outputs)
KV_SERIALIZE(extra)
END_KV_SERIALIZE_MAP()
};
struct request
{
std::string unsigned_txset;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(unsigned_txset)
END_KV_SERIALIZE_MAP()
};
struct response
{
std::list<transfer_description> desc;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(desc)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_SIGN_TRANSFER
{
struct request
{
std::string unsigned_txset;
bool export_raw;
bool get_tx_keys;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(unsigned_txset)
KV_SERIALIZE_OPT(export_raw, false)
KV_SERIALIZE_OPT(get_tx_keys, false)
END_KV_SERIALIZE_MAP()
};
@ -550,11 +613,13 @@ namespace wallet_rpc
std::string signed_txset;
std::list<std::string> tx_hash_list;
std::list<std::string> tx_raw_list;
std::list<std::string> tx_key_list;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(signed_txset)
KV_SERIALIZE(tx_hash_list)
KV_SERIALIZE(tx_raw_list)
KV_SERIALIZE(tx_key_list)
END_KV_SERIALIZE_MAP()
};
};