forked from lthn/blockchain
Merge branch 'mobile' into develop
This commit is contained in:
commit
1b94af5444
30 changed files with 915 additions and 73 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,4 +1,5 @@
|
|||
/build*
|
||||
/_builds/*
|
||||
/tags
|
||||
.DS_Store
|
||||
._.DS_Store
|
||||
|
|
|
|||
|
|
@ -5,13 +5,17 @@ PROJECT(Zano)
|
|||
|
||||
set(VERSION "1.0")
|
||||
|
||||
if(POLICY CMP0043)
|
||||
cmake_policy(SET CMP0043 OLD)
|
||||
endif()
|
||||
# if(POLICY CMP0043)
|
||||
# cmake_policy(SET CMP0043 OLD)
|
||||
# endif()
|
||||
|
||||
if(POLICY CMP0020)
|
||||
cmake_policy(SET CMP0020 OLD)
|
||||
endif()
|
||||
# if(POLICY CMP0020)
|
||||
# cmake_policy(SET CMP0020 OLD)
|
||||
# endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
add_definitions(-DIOS_BUILD)
|
||||
endif()
|
||||
|
||||
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
|
@ -24,7 +28,11 @@ if (UNIX AND NOT APPLE)
|
|||
endif()
|
||||
else()
|
||||
# multi configurations for MSVC and XCode
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(CMAKE_CONFIGURATION_TYPES "Release")
|
||||
else()
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
||||
endif()
|
||||
endif()
|
||||
message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}, and built type: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
|
|
@ -78,7 +86,7 @@ else()
|
|||
else()
|
||||
set(ARCH_FLAG "-march=${ARCH}")
|
||||
endif()
|
||||
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return")
|
||||
set(WARNINGS "-Wno-implicit-function-declaration -Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return")
|
||||
# if(NOT APPLE)
|
||||
# set(WARNINGS "${WARNINGS} -Werror")
|
||||
# endif()
|
||||
|
|
@ -161,11 +169,19 @@ if(STATIC)
|
|||
set(Boost_USE_STATIC_LIBS ON)
|
||||
set(Boost_USE_STATIC_RUNTIME ON)
|
||||
endif()
|
||||
find_package(Boost 1.53 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
|
||||
if(MSVC AND (${Boost_MAJOR_VERSION} EQUAL 1) AND (${Boost_MINOR_VERSION} EQUAL 54))
|
||||
message(SEND_ERROR "Boost version 1.54 is unsupported, more details are available here http://goo.gl/RrCFmA")
|
||||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
set(Boost_INCLUDE_DIRS "/Users/roky/projects/Zano/mobile_repo/ofxiOSBoost/libs/boost/include")
|
||||
set(Boost_LIBRARY_DIRS "/Users/roky/projects/Zano/mobile_repo/ofxiOSBoost/libs/boost/ios/")
|
||||
set(Boost_LIBRARIES "libboost.a")
|
||||
set(Boost_VERSION "ofxiOSBoost 1.60.0")
|
||||
else()
|
||||
find_package(Boost 1.55 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
message(STATUS "Boost: ${Boost_VERSION} from ${Boost_LIBRARY_DIRS}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,24 @@
|
|||
set(UPNPC_BUILD_STATIC ON CACHE BOOL "Build static library")
|
||||
set(UPNPC_BUILD_SHARED OFF CACHE BOOL "Build shared library")
|
||||
set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Build test executables")
|
||||
add_subdirectory(miniupnp/miniupnpc)
|
||||
add_subdirectory(zlib)
|
||||
add_subdirectory(db)
|
||||
add_subdirectory(ethereum)
|
||||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
message("excluded upnp support for IOS build")
|
||||
return()
|
||||
endif()
|
||||
add_subdirectory(miniupnp/miniupnpc)
|
||||
|
||||
|
||||
set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET mdbx PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET lmdb PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat minigzip zlib example PROPERTY FOLDER "unused")
|
||||
|
||||
if(MSVC)
|
||||
set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
message("excluded db support for IOS build")
|
||||
return()
|
||||
endif()
|
||||
|
||||
|
||||
message("DB ENGINE: lmdb")
|
||||
add_subdirectory(liblmdb)
|
||||
if(MSVC)
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@ namespace epee
|
|||
template<typename t_proxy_object, typename t_proxy_lock_time_watching_policy>
|
||||
friend class locked_object_proxy;
|
||||
public:
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> lock()
|
||||
{
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> res;
|
||||
res.reset(new locked_object_proxy<t_object, lock_time_watching_policy>(t, m));
|
||||
return res;
|
||||
}
|
||||
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> try_lock()
|
||||
{
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> res;
|
||||
|
|
|
|||
|
|
@ -183,10 +183,10 @@ if(MINGW)
|
|||
set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
|
||||
endif(MINGW)
|
||||
|
||||
add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
|
||||
#add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
|
||||
add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
|
||||
set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
|
||||
set_target_properties(zlib PROPERTIES SOVERSION 1)
|
||||
# set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
|
||||
# set_target_properties(zlib PROPERTIES SOVERSION 1)
|
||||
|
||||
if(NOT CYGWIN)
|
||||
# This property causes shared libraries on Linux to have the full version
|
||||
|
|
@ -196,22 +196,22 @@ if(NOT CYGWIN)
|
|||
#
|
||||
# This has no effect with MSVC, on that platform the version info for
|
||||
# the DLL comes from the resource file win32/zlib1.rc
|
||||
set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION})
|
||||
# set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION})
|
||||
endif()
|
||||
|
||||
if(UNIX)
|
||||
# On unix-like platforms the library is almost always called libz
|
||||
set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z)
|
||||
set_target_properties( zlibstatic PROPERTIES OUTPUT_NAME z)
|
||||
if(NOT APPLE)
|
||||
set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"")
|
||||
#set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"")
|
||||
endif()
|
||||
elseif(BUILD_SHARED_LIBS AND WIN32)
|
||||
# Creates zlib1.dll when building shared library version
|
||||
set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
|
||||
# set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
|
||||
endif()
|
||||
|
||||
if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
|
||||
install(TARGETS zlib zlibstatic
|
||||
install(TARGETS zlibstatic
|
||||
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
|
||||
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
|
||||
LIBRARY DESTINATION "${INSTALL_LIB_DIR}" )
|
||||
|
|
@ -230,20 +230,20 @@ endif()
|
|||
# Example binaries
|
||||
#============================================================================
|
||||
|
||||
add_executable(example test/example.c)
|
||||
target_link_libraries(example zlib)
|
||||
add_test(example example)
|
||||
#add_executable(example test/example.c)
|
||||
#target_link_libraries(example zlib)
|
||||
#add_test(example example)
|
||||
|
||||
add_executable(minigzip test/minigzip.c)
|
||||
target_link_libraries(minigzip zlib)
|
||||
#add_executable(minigzip test/minigzip.c)
|
||||
#target_link_libraries(minigzip zlib)
|
||||
|
||||
if(HAVE_OFF64_T)
|
||||
add_executable(example64 test/example.c)
|
||||
target_link_libraries(example64 zlib)
|
||||
set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
|
||||
add_test(example64 example64)
|
||||
# add_executable(example64 test/example.c)
|
||||
# target_link_libraries(example64 zlib)
|
||||
# set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
|
||||
# add_test(example64 example64)
|
||||
|
||||
add_executable(minigzip64 test/minigzip.c)
|
||||
target_link_libraries(minigzip64 zlib)
|
||||
set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
|
||||
# add_executable(minigzip64 test/minigzip.c)
|
||||
# target_link_libraries(minigzip64 zlib)
|
||||
# set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
if(POLICY CMP0043)
|
||||
cmake_policy(SET CMP0043 OLD)
|
||||
endif()
|
||||
# if(POLICY CMP0043)
|
||||
# cmake_policy(SET CMP0043 OLD)
|
||||
# endif()
|
||||
|
||||
###########
|
||||
# using shared PCH -- this is unusual case for MSVC... so mystery, such hack, many wow. See also: https://stackoverflow.com/questions/645747/sharing-precompiled-headers-between-projects-in-visual-studio/4170902#4170902
|
||||
|
|
@ -99,10 +98,20 @@ endif()
|
|||
|
||||
add_library(crypto ${CRYPTO})
|
||||
|
||||
add_library(wallet ${WALLET})
|
||||
add_dependencies(wallet version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(WALLET)
|
||||
|
||||
add_library(currency_core ${CURRENCY_CORE})
|
||||
add_dependencies(currency_core version rpc ${PCH_LIB_NAME})
|
||||
add_dependencies(currency_core version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(CURRENCY_CORE)
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
|
||||
install(TARGETS wallet currency_core crypto common DESTINATION lib)
|
||||
message("Generating for iOS: finished")
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_library(rpc ${RPC})
|
||||
add_dependencies(rpc version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(RPC)
|
||||
|
|
@ -111,9 +120,6 @@ add_library(stratum ${STRATUM})
|
|||
add_dependencies(stratum version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(STRATUM)
|
||||
|
||||
add_library(wallet ${WALLET})
|
||||
add_dependencies(wallet version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(WALLET)
|
||||
|
||||
target_link_libraries(currency_core lmdb mdbx)
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ using namespace currency;
|
|||
#endif
|
||||
#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20
|
||||
|
||||
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1"
|
||||
|
||||
DISABLE_VS_WARNINGS(4267)
|
||||
|
||||
|
|
|
|||
|
|
@ -192,7 +192,9 @@
|
|||
|
||||
|
||||
#define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_"
|
||||
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
|
||||
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_"
|
||||
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1"
|
||||
|
||||
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
|
||||
#define MINER_CONFIG_FILENAME "miner_conf.json"
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ namespace currency {
|
|||
using std::uint64_t;
|
||||
using std::vector;
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <windows.h>
|
||||
#include <winnt.h>
|
||||
//#if defined(_MSC_VER)
|
||||
//#include <windows.h>
|
||||
//#include <winnt.h>
|
||||
|
||||
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
|
||||
boost::multiprecision::uint128_t res = boost::multiprecision::uint128_t(a) * b;
|
||||
|
|
@ -36,7 +36,7 @@ namespace currency {
|
|||
//low = UnsignedMultiply128(a, b, &high);
|
||||
}
|
||||
|
||||
#else
|
||||
/* #else
|
||||
|
||||
static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) {
|
||||
typedef unsigned __int128 uint128_t;
|
||||
|
|
@ -45,7 +45,7 @@ namespace currency {
|
|||
high = (uint64_t)(res >> 64);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif */
|
||||
|
||||
static inline bool cadd(uint64_t a, uint64_t b) {
|
||||
return a + b < a;
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated
|
|||
#define TRANSACTION_POOL_OPTIONS_ID_STORAGE_MAJOR_COMPATIBILITY_VERSION 92 // DON'T CHANGE THIS, if you need to resync db! Change TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION instead!
|
||||
#define TRANSACTION_POOL_MAJOR_COMPATIBILITY_VERSION BLOCKCHAIN_STORAGE_MAJOR_COMPATIBILITY_VERSION + 1
|
||||
|
||||
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
|
||||
|
||||
#define CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL 50 // if there's a conflict in key images between tx in the pool and in the blockchain this much depth in required to remove correspongin tx from pool
|
||||
|
||||
|
|
@ -1165,7 +1164,7 @@ namespace currency
|
|||
uint64_t cache_size_l1 = CACHE_SIZE;
|
||||
LOG_PRINT_GREEN("Using pool db file cache size(L1): " << cache_size_l1, LOG_LEVEL_0);
|
||||
|
||||
// remove old incompartible DB
|
||||
// remove old incompatible DB
|
||||
const std::string old_db_folder_path = m_config_folder + "/" CURRENCY_POOLDATA_FOLDERNAME_OLD;
|
||||
if (boost::filesystem::exists(epee::string_encoding::utf8_to_wstring(old_db_folder_path)))
|
||||
{
|
||||
|
|
@ -1192,8 +1191,6 @@ namespace currency
|
|||
|
||||
res = m_db_transactions.init(TRANSACTION_POOL_CONTAINER_TRANSACTIONS);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
// res = m_db_key_images_set.init(TRANSACTION_POOL_CONTAINER_KEY_IMAGES);
|
||||
// CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
res = m_db_black_tx_list.init(TRANSACTION_POOL_CONTAINER_BLACK_TX_LIST);
|
||||
CHECK_AND_ASSERT_MES(res, false, "Unable to init db container");
|
||||
res = m_db_alias_names.init(TRANSACTION_POOL_CONTAINER_ALIAS_NAMES);
|
||||
|
|
|
|||
|
|
@ -171,7 +171,6 @@ namespace currency
|
|||
|
||||
transactions_container m_db_transactions;
|
||||
hash_container m_db_black_tx_list;
|
||||
//key_images_container m_db_key_images_set;
|
||||
aliases_container m_db_alias_names;
|
||||
address_to_aliases_container m_db_alias_addresses;
|
||||
solo_options_container m_db_solo_options;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include "string_coding.h"
|
||||
#include "currency_core/core_tools.h"
|
||||
#include "common/callstack_helper.h"
|
||||
#include "wallet/wallet_helpers.h"
|
||||
|
||||
#define GET_WALLET_OPT_BY_ID(wallet_id, name) \
|
||||
CRITICAL_REGION_LOCAL(m_wallets_lock); \
|
||||
|
|
@ -1342,14 +1343,12 @@ std::string daemon_backend::run_wallet(uint64_t wallet_id)
|
|||
wo.miner_thread = std::thread(boost::bind(&daemon_backend::wallet_vs_options::worker_func, &wo));
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
|
||||
std::string daemon_backend::get_wallet_info(wallet_vs_options& wo, view::wallet_info& wi)
|
||||
{
|
||||
wi = view::wallet_info();
|
||||
wi.address = wo.w->get()->get_account().get_public_address_str();
|
||||
wi.tracking_hey = string_tools::pod_to_hex(wo.w->get()->get_account().get_keys().m_view_secret_key);
|
||||
uint64_t fake = 0;
|
||||
wi.balance = wo.w->get()->balance(wi.unlocked_balance, fake, fake, wi.mined_total);
|
||||
wi.path = epee::string_encoding::wstring_to_utf8(wo.w->get()->get_wallet_path());
|
||||
auto locker_object = wo.w.lock();
|
||||
tools::wallet2& rw = *(*(*locker_object)); //this looks a bit crazy, i know
|
||||
tools::get_wallet_info(rw, wi);
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <QObject>
|
||||
#ifndef Q_MOC_RUN
|
||||
// #include <stdint.h>
|
||||
// #include <QObject>
|
||||
// #ifndef Q_MOC_RUN
|
||||
#include "warnings.h"
|
||||
|
||||
PUSH_VS_WARNINGS
|
||||
|
|
@ -22,7 +22,7 @@ DISABLE_VS_WARNINGS(4503)
|
|||
#include "currency_core/basic_api_response_codes.h"
|
||||
POP_VS_WARNINGS
|
||||
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
namespace view
|
||||
{
|
||||
|
|
|
|||
|
|
@ -155,7 +155,6 @@ namespace currency
|
|||
MAP_JON_RPC ("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN)
|
||||
//
|
||||
MAP_JON_RPC_WE("marketplace_global_get_offers_ex", on_get_offers_ex, COMMAND_RPC_GET_OFFERS_EX)
|
||||
|
||||
//remote miner rpc
|
||||
MAP_JON_RPC_N(on_login, mining::COMMAND_RPC_LOGIN)
|
||||
MAP_JON_RPC_N(on_getjob, mining::COMMAND_RPC_GETJOB)
|
||||
|
|
|
|||
155
src/wallet/plain_wallet_api.cpp
Normal file
155
src/wallet/plain_wallet_api.cpp
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include "plain_wallet_api.h"
|
||||
#include "plain_wallet_api_impl.h"
|
||||
#include "currency_core/currency_config.h"
|
||||
#include "version.h"
|
||||
|
||||
//TODO: global objects, need refactoring. Just temporary solution
|
||||
std::map<int64_t, plain_wallet::plain_wallet_api_impl*> ginstances;
|
||||
epee::critical_section ginstances_lock;
|
||||
std::atomic<int64_t> gcounter(1);
|
||||
std::atomic<bool> glogs_initialized(false);
|
||||
|
||||
#define GENERAL_INTERNAL_ERRROR_INSTANCE "GENERAL_INTERNAL_ERROR: WALLET INSTNACE NOT FOUND"
|
||||
|
||||
#define GET_INSTANCE(var_name, instance_handle) plain_wallet_api_impl* var_name = nullptr;\
|
||||
CRITICAL_REGION_BEGIN(ginstances_lock);\
|
||||
auto it = ginstances.find(instance_handle);\
|
||||
if (it == ginstances.end())\
|
||||
{\
|
||||
LOG_ERROR("Internall error: attempt to get instance wallet with wrong id: " << instance_handle);\
|
||||
return GENERAL_INTERNAL_ERRROR_INSTANCE;\
|
||||
}\
|
||||
var_name = it->second;\
|
||||
CRITICAL_REGION_END();
|
||||
|
||||
|
||||
|
||||
|
||||
namespace plain_wallet
|
||||
{
|
||||
std::string get_bundle_root_dir()
|
||||
{
|
||||
char buffer[1000] = {0};
|
||||
strcpy(buffer, getenv("HOME"));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::string get_wallets_folder()
|
||||
{
|
||||
return get_bundle_root_dir() + "/Documents";
|
||||
}
|
||||
|
||||
void initialize_logs()
|
||||
{
|
||||
std::string log_dir = get_bundle_root_dir();
|
||||
log_dir += "/Documents";
|
||||
epee::log_space::get_set_log_detalisation_level(true, LOG_LEVEL_2);
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
|
||||
epee::log_space::log_singletone::add_logger(LOGGER_FILE, "plain_wallet.log", log_dir.c_str());
|
||||
LOG_PRINT_L0("Plain wallet initialized: " << CURRENCY_NAME << " v" << PROJECT_VERSION_LONG << ", log location: " << log_dir + "/plain_wallet.log");
|
||||
|
||||
glogs_initialized = true;
|
||||
}
|
||||
|
||||
std::string get_version()
|
||||
{
|
||||
return PROJECT_VERSION_LONG;
|
||||
}
|
||||
|
||||
struct strings_list
|
||||
{
|
||||
std::list<std::string> items;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(items)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
|
||||
};
|
||||
|
||||
std::string get_wallet_files()
|
||||
{
|
||||
std::string wallet_files_path = get_wallets_folder();
|
||||
strings_list sl = AUTO_VAL_INIT(sl);
|
||||
epee::file_io_utils::get_folder_content(wallet_files_path, sl.items, true);
|
||||
return epee::serialization::store_t_to_json(sl);
|
||||
}
|
||||
|
||||
hwallet create_instance(const std::string& ip, const std::string& port)
|
||||
{
|
||||
if (!glogs_initialized)
|
||||
initialize_logs();
|
||||
|
||||
plain_wallet_api_impl* ptr = new plain_wallet_api_impl(ip, port);
|
||||
hwallet new_h = gcounter++;
|
||||
CRITICAL_REGION_BEGIN(ginstances_lock);
|
||||
ginstances[new_h] = ptr;
|
||||
CRITICAL_REGION_END();
|
||||
return new_h;
|
||||
}
|
||||
|
||||
void destroy_instance(hwallet h)
|
||||
{
|
||||
plain_wallet_api_impl* instance_ptr = nullptr;
|
||||
CRITICAL_REGION_BEGIN(ginstances_lock);
|
||||
auto it = ginstances.find(h);
|
||||
if (it == ginstances.end())
|
||||
{
|
||||
LOG_ERROR("Internall error: attempt to delete wallet with wrong instance id: " << h);
|
||||
}
|
||||
instance_ptr = it->second;
|
||||
ginstances.erase(it);
|
||||
CRITICAL_REGION_END();
|
||||
delete instance_ptr;
|
||||
}
|
||||
std::string open(hwallet h, const std::string& path, const std::string& password)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
std::string full_path = get_wallets_folder() + "/" + path;
|
||||
return pimpl->open(full_path, password);
|
||||
}
|
||||
std::string restore(hwallet h, const std::string& seed, const std::string& path, const std::string& password)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
std::string full_path = get_wallets_folder() + "/" + path;
|
||||
return pimpl->restore(seed, full_path, password);
|
||||
}
|
||||
std::string generate(hwallet h, const std::string& path, const std::string& password)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
std::string full_path = get_wallets_folder() + "/" + path;
|
||||
return pimpl->generate(full_path, password);
|
||||
}
|
||||
std::string start_sync_thread(hwallet h)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
pimpl->start_sync_thread();
|
||||
return "";
|
||||
}
|
||||
std::string get_sync_status(hwallet h)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
return pimpl->get_sync_status();
|
||||
}
|
||||
|
||||
std::string cancel_sync_thread(hwallet h)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
return pimpl->cancel_sync_thread();
|
||||
}
|
||||
|
||||
std::string sync(hwallet h)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
return pimpl->sync();
|
||||
}
|
||||
std::string invoke(hwallet h, const std::string& params)
|
||||
{
|
||||
GET_INSTANCE(pimpl, h);
|
||||
return pimpl->invoke(params);
|
||||
}
|
||||
}
|
||||
27
src/wallet/plain_wallet_api.h
Normal file
27
src/wallet/plain_wallet_api.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace plain_wallet
|
||||
{
|
||||
typedef int64_t hwallet;
|
||||
hwallet create_instance(const std::string& ip, const std::string& port);
|
||||
void destroy_instance(hwallet h);
|
||||
std::string get_version();
|
||||
std::string get_wallet_files();
|
||||
|
||||
std::string open(hwallet h, const std::string& path, const std::string& password);
|
||||
std::string restore(hwallet h, const std::string& seed, const std::string& path, const std::string& password);
|
||||
std::string generate(hwallet h, const std::string& path, const std::string& password);
|
||||
|
||||
std::string start_sync_thread(hwallet h);
|
||||
std::string get_sync_status(hwallet h);
|
||||
std::string cancel_sync_thread(hwallet h);
|
||||
std::string sync(hwallet h);
|
||||
std::string invoke(hwallet h, const std::string& params);
|
||||
}
|
||||
50
src/wallet/plain_wallet_api_defs.h
Normal file
50
src/wallet/plain_wallet_api_defs.h
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include "net/http_server_handlers_map2.h"
|
||||
#include "gui/qt-daemon/application/view_iface.h"
|
||||
|
||||
namespace plain_wallet
|
||||
{
|
||||
struct error
|
||||
{
|
||||
std::string code;
|
||||
std::string message;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(code)
|
||||
KV_SERIALIZE(message)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
||||
struct open_wallet_response
|
||||
{
|
||||
view::transfers_array recent_history;
|
||||
view::wallet_info wi;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(recent_history)
|
||||
KV_SERIALIZE(wi)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct sync_status_response
|
||||
{
|
||||
bool finished;
|
||||
uint64_t progress;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(finished)
|
||||
KV_SERIALIZE(progress)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct basic_status_response
|
||||
{
|
||||
std::string status;
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
} // namespace tools
|
||||
176
src/wallet/plain_wallet_api_impl.cpp
Normal file
176
src/wallet/plain_wallet_api_impl.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "plain_wallet_api_impl.h"
|
||||
#include "wallet/wallet_helpers.h"
|
||||
|
||||
namespace plain_wallet
|
||||
{
|
||||
typedef epee::json_rpc::response<epee::json_rpc::dummy_result, error> error_response;
|
||||
|
||||
plain_wallet_api_impl::plain_wallet_api_impl(const std::string& ip, const std::string& port):
|
||||
m_stop(false),
|
||||
m_sync_finished(false)
|
||||
{
|
||||
m_wallet.reset(new tools::wallet2());
|
||||
m_wallet->init(ip + ":" + port);
|
||||
m_rpc_wrapper.reset(new tools::wallet_rpc_server(*m_wallet));
|
||||
}
|
||||
|
||||
plain_wallet_api_impl::~plain_wallet_api_impl()
|
||||
{
|
||||
if (m_sync_thread.joinable())
|
||||
m_sync_thread.join();
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::open(const std::string& path, const std::string& password)
|
||||
{
|
||||
error_response err_result = AUTO_VAL_INIT(err_result);
|
||||
try
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
m_wallet->load(epee::string_encoding::utf8_to_wstring(path), password);
|
||||
epee::json_rpc::response<open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
m_wallet->get_recent_transfers_history(ok_response.result.recent_history.history, 0, 20, ok_response.result.recent_history.total_history_items);
|
||||
m_wallet->get_unconfirmed_transfers(ok_response.result.recent_history.history);
|
||||
tools::get_wallet_info(*m_wallet, ok_response.result.wi);
|
||||
return epee::serialization::store_t_to_json(ok_response);
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize was with problems, but still worked : " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FILE_RESTORED;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize failed: " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FAIL;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::restore(const std::string& seed, const std::string& path, const std::string& password)
|
||||
{
|
||||
error_response err_result = AUTO_VAL_INIT(err_result);
|
||||
try
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
m_wallet->restore(epee::string_encoding::utf8_to_wstring(path), password, seed);
|
||||
epee::json_rpc::response<open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
tools::get_wallet_info(*m_wallet, ok_response.result.wi);
|
||||
return epee::serialization::store_t_to_json(ok_response);
|
||||
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize was with problems, but still worked : " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FILE_RESTORED;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize failed: " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FAIL;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::generate(const std::string& path, const std::string& password)
|
||||
{
|
||||
error_response err_result = AUTO_VAL_INIT(err_result);
|
||||
try
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
m_wallet->generate(epee::string_encoding::utf8_to_wstring(path), password);
|
||||
epee::json_rpc::response<open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
tools::get_wallet_info(*m_wallet, ok_response.result.wi);
|
||||
return epee::serialization::store_t_to_json(ok_response);
|
||||
}
|
||||
catch (const tools::error::wallet_load_notice_wallet_restored& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize was with problems, but still worked : " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FILE_RESTORED;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Wallet initialize failed: " << e.what());
|
||||
err_result.error.code = API_RETURN_CODE_FAIL;
|
||||
return epee::serialization::store_t_to_json(err_result);
|
||||
}
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::start_sync_thread()
|
||||
{
|
||||
m_sync_thread = std::thread([&]()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
m_wallet->refresh(m_stop);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Wallet refresh failed: " << e.what());
|
||||
return;
|
||||
}
|
||||
m_sync_finished = true;
|
||||
});
|
||||
basic_status_response bsr = AUTO_VAL_INIT(bsr);
|
||||
bsr.status = API_RETURN_CODE_OK;
|
||||
return epee::serialization::store_t_to_json(bsr);
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::cancel_sync_thread()
|
||||
{
|
||||
m_stop = true;
|
||||
if (m_sync_thread.joinable())
|
||||
m_sync_thread.join();
|
||||
basic_status_response bsr = AUTO_VAL_INIT(bsr);
|
||||
bsr.status = API_RETURN_CODE_OK;
|
||||
return epee::serialization::store_t_to_json(bsr);
|
||||
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::get_sync_status()
|
||||
{
|
||||
sync_status_response ssr = AUTO_VAL_INIT(ssr);
|
||||
ssr.finished = m_sync_finished;
|
||||
ssr.progress = m_wallet->get_sync_progress();
|
||||
return epee::serialization::store_t_to_json(ssr);
|
||||
}
|
||||
|
||||
std::string plain_wallet_api_impl::sync()
|
||||
{
|
||||
basic_status_response bsr = AUTO_VAL_INIT(bsr);
|
||||
try
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
m_wallet->refresh(m_stop);
|
||||
bsr.status = API_RETURN_CODE_OK;
|
||||
return epee::serialization::store_t_to_json(bsr);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
LOG_ERROR("Wallet refresh failed: " << e.what());
|
||||
bsr.status = API_RETURN_CODE_FAIL;
|
||||
return epee::serialization::store_t_to_json(bsr);
|
||||
}
|
||||
}
|
||||
std::string plain_wallet_api_impl::invoke(const std::string& params)
|
||||
{
|
||||
CRITICAL_REGION_LOCAL(m_wallet_lock);
|
||||
epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info);
|
||||
epee::net_utils::http::http_response_info response_info = AUTO_VAL_INIT(response_info);
|
||||
epee::net_utils::connection_context_base stub_conn_context = AUTO_VAL_INIT(stub_conn_context);
|
||||
std::string reference_stub;
|
||||
bool call_found = false;
|
||||
query_info.m_URI = "/json_rpc";
|
||||
query_info.m_body = params;
|
||||
m_rpc_wrapper->handle_http_request_map(query_info, response_info, stub_conn_context, call_found, reference_stub);
|
||||
return response_info.m_body;
|
||||
}
|
||||
}
|
||||
40
src/wallet/plain_wallet_api_impl.h
Normal file
40
src/wallet/plain_wallet_api_impl.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "wallet2.h"
|
||||
#include "wallet_rpc_server.h"
|
||||
#include "plain_wallet_api_defs.h"
|
||||
|
||||
namespace plain_wallet
|
||||
{
|
||||
class plain_wallet_api_impl
|
||||
{
|
||||
public:
|
||||
plain_wallet_api_impl(const std::string& ip, const std::string& port);
|
||||
~plain_wallet_api_impl();
|
||||
std::string open(const std::string& path, const std::string& password);
|
||||
std::string restore(const std::string& seed, const std::string& path, const std::string& password);
|
||||
std::string generate(const std::string& path, const std::string& password);
|
||||
|
||||
std::string start_sync_thread();
|
||||
std::string cancel_sync_thread();
|
||||
std::string get_sync_status();
|
||||
|
||||
std::string sync();
|
||||
std::string invoke(const std::string& params);
|
||||
private:
|
||||
bool get_wallet_info(view::wallet_info& wi);
|
||||
std::thread m_sync_thread;
|
||||
epee::critical_section m_wallet_lock;
|
||||
std::atomic<bool> m_stop;
|
||||
std::atomic<bool> m_sync_finished;
|
||||
std::shared_ptr<tools::wallet2> m_wallet;
|
||||
std::shared_ptr<tools::wallet_rpc_server> m_rpc_wrapper;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1236,6 +1236,11 @@ void wallet2::handle_pulled_blocks(size_t& blocks_added, std::atomic<bool>& stop
|
|||
WLT_LOG_L1("[PULL BLOCKS] " << res.start_height << " --> " << m_blockchain.size());
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_sync_progress()
|
||||
{
|
||||
return m_last_sync_percent;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::refresh()
|
||||
{
|
||||
size_t blocks_fetched = 0;
|
||||
|
|
@ -2584,6 +2589,11 @@ uint64_t wallet2::get_recent_transfers_total_count()
|
|||
return m_transfer_history.size();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
uint64_t wallet2::get_transfer_entries_count()
|
||||
{
|
||||
return m_transfers.size();
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count, uint64_t& total)
|
||||
{
|
||||
if (offset >= m_transfer_history.size())
|
||||
|
|
|
|||
|
|
@ -452,9 +452,9 @@ namespace tools
|
|||
END_SERIALIZE()
|
||||
};
|
||||
void assign_account(const currency::account_base& acc);
|
||||
void generate(const std::wstring& wallet, const std::string& password);
|
||||
void generate(const std::wstring& path, const std::string& password);
|
||||
void restore(const std::wstring& path, const std::string& pass, const std::string& restore_key);
|
||||
void load(const std::wstring& wallet, const std::string& password);
|
||||
void load(const std::wstring& path, const std::string& password);
|
||||
void store();
|
||||
void store(const std::wstring& path);
|
||||
void store(const std::wstring& path, const std::string& password);
|
||||
|
|
@ -466,6 +466,7 @@ namespace tools
|
|||
|
||||
void get_recent_transfers_history(std::vector<wallet_public::wallet_transfer_info>& trs, size_t offset, size_t count, uint64_t& total);
|
||||
uint64_t get_recent_transfers_total_count();
|
||||
uint64_t get_transfer_entries_count();
|
||||
void get_unconfirmed_transfers(std::vector<wallet_public::wallet_transfer_info>& trs);
|
||||
void init(const std::string& daemon_address = "http://localhost:8080");
|
||||
bool deinit();
|
||||
|
|
@ -744,7 +745,7 @@ namespace tools
|
|||
std::string get_log_prefix() const { return m_log_prefix; }
|
||||
static uint64_t get_max_unlock_time_from_receive_indices(const currency::transaction& tx, const money_transfer2_details& td);
|
||||
bool get_utxo_distribution(std::map<uint64_t, uint64_t>& distribution);
|
||||
|
||||
uint64_t get_sync_progress();
|
||||
private:
|
||||
void add_transfers_to_expiration_list(const std::vector<uint64_t>& selected_transfers, uint64_t expiration, uint64_t change_amount, const crypto::hash& related_tx_id);
|
||||
void remove_transfer_from_expiration_list(uint64_t transfer_index);
|
||||
|
|
@ -895,7 +896,7 @@ private:
|
|||
std::shared_ptr<i_core_proxy> m_core_proxy;
|
||||
std::shared_ptr<i_wallet2_callback> m_wcallback;
|
||||
uint64_t m_height_of_start_sync;
|
||||
uint64_t m_last_sync_percent;
|
||||
std::atomic<uint64_t> m_last_sync_percent;
|
||||
uint64_t m_last_pow_block_h;
|
||||
currency::core_runtime_config m_core_runtime_config;
|
||||
escrow_contracts_container m_contracts;
|
||||
|
|
|
|||
24
src/wallet/wallet_helpers.h
Normal file
24
src/wallet/wallet_helpers.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2014-2020 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "wallet2.h"
|
||||
#include "gui/qt-daemon/application/view_iface.h"
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
inline bool get_wallet_info(wallet2& w, view::wallet_info& wi)
|
||||
{
|
||||
wi = AUTO_VAL_INIT_T(view::wallet_info);
|
||||
wi.address = w.get_account().get_public_address_str();
|
||||
wi.tracking_hey = epee::string_tools::pod_to_hex(w.get_account().get_keys().m_view_secret_key);
|
||||
uint64_t fake = 0;
|
||||
wi.balance = w.balance(wi.unlocked_balance, fake, fake, wi.mined_total);
|
||||
wi.path = epee::string_encoding::wstring_to_utf8(w.get_wallet_path());
|
||||
return API_RETURN_CODE_OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#pragma once
|
||||
#include <vector>
|
||||
#include "currency_protocol/currency_protocol_defs.h"
|
||||
#include "currency_core/currency_basic.h"
|
||||
#include "crypto/hash.h"
|
||||
|
|
@ -206,6 +207,97 @@ namespace wallet_public
|
|||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct COMMAND_RPC_GET_WALLET_INFO
|
||||
{
|
||||
struct request
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::string address;
|
||||
std::string path;
|
||||
uint64_t transfers_count;
|
||||
uint64_t transfer_entries_count;
|
||||
bool is_whatch_only;
|
||||
std::vector<std::string> utxo_distribution;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(address)
|
||||
KV_SERIALIZE(path)
|
||||
KV_SERIALIZE(transfers_count)
|
||||
KV_SERIALIZE(transfer_entries_count)
|
||||
KV_SERIALIZE(is_whatch_only)
|
||||
KV_SERIALIZE(utxo_distribution)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct wallet_provision_info
|
||||
{
|
||||
uint64_t transfers_count;
|
||||
uint64_t transfer_entries_count;
|
||||
uint64_t balance;
|
||||
uint64_t unlocked_balance;
|
||||
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(transfers_count)
|
||||
KV_SERIALIZE(transfer_entries_count)
|
||||
KV_SERIALIZE(balance)
|
||||
KV_SERIALIZE(unlocked_balance)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct COMMAND_RPC_GET_RECENT_TXS_AND_INFO
|
||||
{
|
||||
struct request
|
||||
{
|
||||
|
||||
/*
|
||||
if offset is 0, then GET_RECENT_TXS_AND_INFO return
|
||||
unconfirmed transactions as the first first items of "transfers",
|
||||
this unconfirmed transactions is not counted regarding "count" parameter
|
||||
*/
|
||||
uint64_t offset;
|
||||
uint64_t count;
|
||||
|
||||
/*
|
||||
need_to_get_info - should backend re-calculate balance(could be relatively heavy,
|
||||
and not needed when getting long tx history with multiple calls
|
||||
of GET_RECENT_TXS_AND_INFO with offsets)
|
||||
*/
|
||||
bool update_provision_info;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(offset)
|
||||
KV_SERIALIZE(count)
|
||||
KV_SERIALIZE(update_provision_info)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
wallet_provision_info pi;
|
||||
std::vector<wallet_transfer_info> transfers;
|
||||
uint64_t total_transfers;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(pi)
|
||||
KV_SERIALIZE(transfers)
|
||||
KV_SERIALIZE(total_transfers)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct trnsfer_destination
|
||||
{
|
||||
uint64_t amount;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ namespace tools
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address)
|
||||
{
|
||||
static const uint64_t wallet_rpt_idle_work_period_ms = 2000;
|
||||
static const uint64_t wallet_rpc_idle_work_period_ms = 2000;
|
||||
|
||||
m_do_mint = do_mint;
|
||||
|
||||
|
|
@ -97,7 +97,7 @@ namespace tools
|
|||
}
|
||||
|
||||
return true;
|
||||
}, wallet_rpt_idle_work_period_ms);
|
||||
}, wallet_rpc_idle_work_period_ms);
|
||||
}
|
||||
|
||||
//DO NOT START THIS SERVER IN MORE THEN 1 THREADS WITHOUT REFACTORING
|
||||
|
|
@ -186,6 +186,54 @@ namespace tools
|
|||
}
|
||||
return true;
|
||||
}
|
||||
bool wallet_rpc_server::on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
try
|
||||
{
|
||||
res.address = m_wallet.get_account().get_public_address_str();
|
||||
res.is_whatch_only = m_wallet.is_watch_only();
|
||||
res.path = epee::string_encoding::convert_to_ansii(m_wallet.get_wallet_path());
|
||||
res.transfers_count = m_wallet.get_recent_transfers_total_count();
|
||||
res.transfer_entries_count = m_wallet.get_transfer_entries_count();
|
||||
std::map<uint64_t, uint64_t> distribution;
|
||||
m_wallet.get_utxo_distribution(distribution);
|
||||
for (const auto& ent : distribution)
|
||||
res.utxo_distribution.push_back(std::to_string(ent.first) + ":" + std::to_string(ent.second));
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool wallet_rpc_server::on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (req.update_provision_info)
|
||||
{
|
||||
res.pi.balance = m_wallet.balance(res.pi.unlocked_balance);
|
||||
res.pi.transfer_entries_count = m_wallet.get_transfer_entries_count();
|
||||
res.pi.transfers_count = m_wallet.get_recent_transfers_total_count();
|
||||
}
|
||||
|
||||
if (req.offset == 0)
|
||||
m_wallet.get_unconfirmed_transfers(res.transfers);
|
||||
|
||||
m_wallet.get_recent_transfers_history(res.transfers, req.offset, req.count, res.total_transfers);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
||||
er.message = e.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
bool wallet_rpc_server::on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@ namespace tools
|
|||
static void init_options(boost::program_options::options_description& desc);
|
||||
bool init(const boost::program_options::variables_map& vm);
|
||||
bool run(bool do_mint, bool offline_mode, const currency::account_public_address& miner_address);
|
||||
|
||||
|
||||
bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response, connection_context& m_conn_context);
|
||||
|
||||
BEGIN_URI_MAP2()
|
||||
BEGIN_JSON_RPC_MAP("/json_rpc")
|
||||
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_public::COMMAND_RPC_GET_BALANCE)
|
||||
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_public::COMMAND_RPC_GET_ADDRESS)
|
||||
MAP_JON_RPC_WE("get_wallet_info", on_getwallet_info, wallet_public::COMMAND_RPC_GET_WALLET_INFO)
|
||||
MAP_JON_RPC_WE("get_recent_txs_and_info", on_get_recent_txs_and_info, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO)
|
||||
MAP_JON_RPC_WE("transfer", on_transfer, wallet_public::COMMAND_RPC_TRANSFER)
|
||||
MAP_JON_RPC_WE("store", on_store, wallet_public::COMMAND_RPC_STORE)
|
||||
MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_public::COMMAND_RPC_GET_PAYMENTS)
|
||||
|
|
@ -68,6 +68,8 @@ namespace tools
|
|||
//json_rpc
|
||||
bool on_getbalance(const wallet_public::COMMAND_RPC_GET_BALANCE::request& req, wallet_public::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_getaddress(const wallet_public::COMMAND_RPC_GET_ADDRESS::request& req, wallet_public::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_getwallet_info(const wallet_public::COMMAND_RPC_GET_WALLET_INFO::request& req, wallet_public::COMMAND_RPC_GET_WALLET_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_get_recent_txs_and_info(const wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::request& req, wallet_public::COMMAND_RPC_GET_RECENT_TXS_AND_INFO::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_transfer(const wallet_public::COMMAND_RPC_TRANSFER::request& req, wallet_public::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_store(const wallet_public::COMMAND_RPC_STORE::request& req, wallet_public::COMMAND_RPC_STORE::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
bool on_get_payments(const wallet_public::COMMAND_RPC_GET_PAYMENTS::request& req, wallet_public::COMMAND_RPC_GET_PAYMENTS::response& res, epee::json_rpc::error& er, connection_context& cntx);
|
||||
|
|
|
|||
|
|
@ -284,8 +284,10 @@ bool generate_events(currency::core& c, cct_events_t& events, const cct_wallets_
|
|||
bool clean_data_directory(boost::program_options::variables_map& vm)
|
||||
{
|
||||
std::string config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
|
||||
const std::string bch_db_folder_path = config_folder + ("/" CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX) + "lmdb" + CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX;
|
||||
const std::string pool_db_folder_path = config_folder + ("/" CURRENCY_POOLDATA_FOLDERNAME_PREFIX) + "lmdb" + CURRENCY_POOLDATA_FOLDERNAME_SUFFIX;
|
||||
|
||||
static const char* const files[] = { CURRENCY_BLOCKCHAINDATA_FOLDERNAME, CURRENCY_POOLDATA_FOLDERNAME, MINER_CONFIG_FILENAME };
|
||||
static const char* const files[] = { bch_db_folder_path.c_str(), pool_db_folder_path.c_str(), MINER_CONFIG_FILENAME };
|
||||
for (size_t i = 0; i < sizeof files / sizeof files[0]; ++i)
|
||||
{
|
||||
boost::filesystem::path filename(config_folder + "/" + files[i]);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ using namespace epee;
|
|||
#include "generate_test_genesis.h"
|
||||
#include "deadlock_guard_test.h"
|
||||
#include "difficulty_analysis.h"
|
||||
#include "plain_wallet_tests.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
||||
|
|
@ -53,6 +54,7 @@ namespace
|
|||
const command_line::arg_descriptor<size_t> arg_generate_test_genesis_json = { "generate-test-genesis-json", "generates test genesis json, specify amount of accounts", 0, true };
|
||||
const command_line::arg_descriptor<bool> arg_deadlock_guard = { "test-deadlock-guard", "Do deadlock guard test", false, true };
|
||||
const command_line::arg_descriptor<std::string> arg_difficulty_analysis = { "difficulty-analysis", "Do difficulty analysis", "", true };
|
||||
const command_line::arg_descriptor<bool> arg_test_plain_wallet = { "test-plainwallet", "Do testing of plain wallet interface", false, true };
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -104,8 +106,7 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_options, arg_max_tx_in_pool);
|
||||
command_line::add_arg(desc_options, arg_deadlock_guard);
|
||||
command_line::add_arg(desc_options, arg_difficulty_analysis);
|
||||
|
||||
|
||||
command_line::add_arg(desc_options, arg_test_plain_wallet);
|
||||
|
||||
|
||||
test_serialization();
|
||||
|
|
@ -190,6 +191,11 @@ int main(int argc, char* argv[])
|
|||
do_deadlock_test_main();
|
||||
return 1;
|
||||
}
|
||||
else if (command_line::has_arg(vm, arg_test_plain_wallet))
|
||||
{
|
||||
run_plain_wallet_api_test();
|
||||
return 1;
|
||||
}
|
||||
else if (command_line::get_arg(vm, arg_test_core_concurrency))
|
||||
{
|
||||
for (size_t i = 0; i != repeat_count; i++)
|
||||
|
|
|
|||
161
tests/functional_tests/plain_wallet_tests.cpp
Normal file
161
tests/functional_tests/plain_wallet_tests.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
||||
#include "include_base_utils.h"
|
||||
using namespace epee;
|
||||
#include "misc_language.h"
|
||||
#include "wallet/plain_wallet_api.h"
|
||||
#include "wallet/wallet_helpers.h"
|
||||
#include "wallet/plain_wallet_api_defs.h"
|
||||
|
||||
|
||||
void run_plain_wallet_api_test()
|
||||
{
|
||||
LOG_PRINT_L0("Creating instance...");
|
||||
plain_wallet::hwallet hw = plain_wallet::create_instance("127.0.0.1", "11211");
|
||||
LOG_PRINT_L0("Creating instance..." << std::hex << hw);
|
||||
|
||||
LOG_PRINT_L0("Generating wallet...");
|
||||
std::string rsp = plain_wallet::open(hw, std::string("E:\\tmp\\zano_testwallet_74565030.zan"), "");
|
||||
LOG_PRINT_L0("RESPONSE:" << ENDL << rsp);
|
||||
epee::json_rpc::response<plain_wallet::open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
epee::serialization::load_t_from_json(ok_response, rsp);
|
||||
|
||||
plain_wallet::start_sync_thread(hw);
|
||||
LOG_PRINT_L0("Started sync thread.");
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::string prog = plain_wallet::get_sync_status(hw);
|
||||
plain_wallet::sync_status_response ssr = AUTO_VAL_INIT(ssr);
|
||||
epee::serialization::load_t_from_json(ssr, prog);
|
||||
LOG_PRINT_L0("Progress: " << ssr.progress << "Finished: " << ssr.finished);
|
||||
if (ssr.finished)
|
||||
break;
|
||||
epee::misc_utils::sleep_no_w(1000);
|
||||
}
|
||||
LOG_PRINT_L0("Sync finished OK");
|
||||
|
||||
{
|
||||
//request get wallet info:
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_GET_WALLET_INFO::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "get_wallet_info";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_GET_WALLET_INFO::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], str_response: "
|
||||
<< ENDL << res);
|
||||
}
|
||||
|
||||
{
|
||||
//request balance
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_GET_BALANCE::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "getbalance";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_GET_BALANCE::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], balance: "
|
||||
<< gbres.result.balance << ", unlocked_balance: " << gbres.result.unlocked_balance);
|
||||
}
|
||||
|
||||
{
|
||||
//request balance
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_STORE::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "store";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_STORE::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], str_response: "
|
||||
<< ENDL << res);
|
||||
}
|
||||
|
||||
plain_wallet::destroy_instance(hw);
|
||||
|
||||
|
||||
return;
|
||||
//-------
|
||||
{
|
||||
LOG_PRINT_L0("Creating instance...");
|
||||
plain_wallet::hwallet hw = plain_wallet::create_instance("127.0.0.1", "11211");
|
||||
LOG_PRINT_L0("Creating instance..." << std::hex << hw);
|
||||
|
||||
LOG_PRINT_L0("Generating wallet...");
|
||||
std::string rsp = plain_wallet::generate(hw, std::string("E:\\tmp\\zano_testwallet_") + std::to_string(epee::misc_utils::get_tick_count()) + ".zan", "");
|
||||
LOG_PRINT_L0("RESPONSE:" << ENDL << rsp);
|
||||
epee::json_rpc::response<plain_wallet::open_wallet_response, epee::json_rpc::dummy_error> ok_response = AUTO_VAL_INIT(ok_response);
|
||||
epee::serialization::load_t_from_json(ok_response, rsp);
|
||||
|
||||
plain_wallet::start_sync_thread(hw);
|
||||
LOG_PRINT_L0("Started sync thread.");
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::string prog = plain_wallet::get_sync_status(hw);
|
||||
plain_wallet::sync_status_response ssr = AUTO_VAL_INIT(ssr);
|
||||
epee::serialization::load_t_from_json(ssr, prog);
|
||||
LOG_PRINT_L0("Progress: " << ssr.progress << "Finished: " << ssr.finished);
|
||||
if (ssr.finished)
|
||||
break;
|
||||
epee::misc_utils::sleep_no_w(1000);
|
||||
}
|
||||
LOG_PRINT_L0("Sync finished OK");
|
||||
|
||||
{
|
||||
//request get wallet info:
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_GET_WALLET_INFO::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "get_wallet_info";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_GET_WALLET_INFO::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], str_response: "
|
||||
<< ENDL << res);
|
||||
}
|
||||
|
||||
{
|
||||
//request balance
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_GET_BALANCE::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "getbalance";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_GET_BALANCE::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], balance: "
|
||||
<< gbres.result.balance << ", unlocked_balance: " << gbres.result.unlocked_balance);
|
||||
}
|
||||
|
||||
{
|
||||
//request balance
|
||||
epee::json_rpc::request<tools::wallet_public::COMMAND_RPC_STORE::request> gbreq = AUTO_VAL_INIT(gbreq);
|
||||
gbreq.method = "store";
|
||||
epee::json_rpc::response<tools::wallet_public::COMMAND_RPC_STORE::response, epee::json_rpc::error> gbres = AUTO_VAL_INIT(gbres);
|
||||
std::string req_str = epee::serialization::store_t_to_json(gbreq);
|
||||
|
||||
std::string res = plain_wallet::invoke(hw, req_str);
|
||||
epee::serialization::load_t_from_json(gbres, res);
|
||||
|
||||
LOG_PRINT_L0("Balance request returned: code [" << gbres.error.code << "], str_response: "
|
||||
<< ENDL << res);
|
||||
}
|
||||
}
|
||||
}
|
||||
9
tests/functional_tests/plain_wallet_tests.h
Normal file
9
tests/functional_tests/plain_wallet_tests.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2014-2018 Zano Project
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
|
||||
void run_plain_wallet_api_test();
|
||||
|
||||
|
||||
Loading…
Add table
Reference in a new issue