diff options
Diffstat (limited to 'src')
47 files changed, 292 insertions, 222 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 28febe6b7..fc7d60e4c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -66,7 +66,7 @@ function (monero_add_executable name) add_executable("${name}" ${ARGN}) target_link_libraries("${name}" - LINK_PRIVATE + PRIVATE ${EXTRA_LIBRARIES}) set_property(TARGET "${name}" PROPERTY @@ -88,7 +88,7 @@ function (monero_add_library name) # libwallet, which combines multiple components. set(objlib obj_${name}) add_library(${objlib} OBJECT ${ARGN}) - add_library("${name}" STATIC $<TARGET_OBJECTS:${objlib}>) + add_library("${name}" $<TARGET_OBJECTS:${objlib}>) set_property(TARGET "${name}" PROPERTY FOLDER "libs") diff --git a/src/blockchain_db/CMakeLists.txt b/src/blockchain_db/CMakeLists.txt index cee7b067e..cefe93ebe 100644 --- a/src/blockchain_db/CMakeLists.txt +++ b/src/blockchain_db/CMakeLists.txt @@ -60,18 +60,12 @@ monero_add_library(blockchain_db ${blockchain_db_headers} ${blockchain_db_private_headers}) target_link_libraries(blockchain_db - LINK_PUBLIC + PUBLIC common crypto - cryptonote_core - ${Boost_DATE_TIME_LIBRARY} - ${Boost_CHRONO_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_SERIALIZATION_LIBRARY} ${LMDB_LIBRARY} ${BDB_LIBRARY} - LINK_PRIVATE ${Boost_FILESYSTEM_LIBRARY} - ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} + PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 8ad875fc8..21ed8f4da 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -1081,7 +1081,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) if (need_resize()) { - LOG_PRINT_L0("LMDB memory map needs resized, doing that now."); + LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now."); do_resize(); } @@ -2500,7 +2500,7 @@ uint64_t BlockchainLMDB::add_block(const block& blk, const size_t& block_size, c // for batch mode, DB resize check is done at start of batch transaction if (! m_batch_active && need_resize()) { - LOG_PRINT_L0("LMDB memory map needs resized, doing that now."); + LOG_PRINT_L0("LMDB memory map needs to be resized, doing that now."); do_resize(); } } diff --git a/src/blockchain_utilities/CMakeLists.txt b/src/blockchain_utilities/CMakeLists.txt index 272798e92..ccfd4a279 100644 --- a/src/blockchain_utilities/CMakeLists.txt +++ b/src/blockchain_utilities/CMakeLists.txt @@ -63,11 +63,15 @@ monero_add_executable(blockchain_import ${blockchain_import_private_headers}) target_link_libraries(blockchain_import - LINK_PRIVATE + PRIVATE cryptonote_core - blockchain_db - p2p - ${CMAKE_THREAD_LIBS_INIT}) + blockchain_db + p2p + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES}) if(ARCH_WIDTH) target_compile_definitions(blockchain_import @@ -85,11 +89,15 @@ monero_add_executable(blockchain_export ${blockchain_export_private_headers}) target_link_libraries(blockchain_export - LINK_PRIVATE + PRIVATE cryptonote_core - p2p - blockchain_db - ${CMAKE_THREAD_LIBS_INIT}) + blockchain_db + p2p + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} + ${EXTRA_LIBRARIES}) add_dependencies(blockchain_export version) diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat Binary files differindex 8a6bed31a..24cfffa38 100644 --- a/src/blocks/checkpoints.dat +++ b/src/blocks/checkpoints.dat diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 654480af3..6bf8b1777 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -62,13 +62,15 @@ monero_add_library(common ${common_headers} ${common_private_headers}) target_link_libraries(common - LINK_PRIVATE + PUBLIC crypto ${UNBOUND_LIBRARY} ${LIBUNWIND_LIBRARIES} ${Boost_DATE_TIME_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + PRIVATE ${EXTRA_LIBRARIES}) #monero_install_headers(common diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index 90db3b04d..fc096abe5 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -48,6 +48,7 @@ namespace command_line const arg_descriptor<bool> arg_version = {"version", "Output version information"}; const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory"}; const arg_descriptor<std::string> arg_testnet_data_dir = {"testnet-data-dir", "Specify testnet data directory"}; + const arg_descriptor<std::string> arg_user_agent = {"user-agent", "Restrict RPC use to clients using this user agent"}; const arg_descriptor<bool> arg_test_drop_download = {"test-drop-download", "For net tests: in download, discard ALL blocks instead checking/saving them (very fast)"}; const arg_descriptor<uint64_t> arg_test_drop_download_height = {"test-drop-download-height", "Like test-drop-download but disards only after around certain height", 0}; const arg_descriptor<int> arg_test_dbg_lock_sleep = {"test-dbg-lock-sleep", "Sleep time in ms, defaults to 0 (off), used to debug before/after locking mutex. Values 100 to 1000 are good for tests."}; diff --git a/src/common/command_line.h b/src/common/command_line.h index 75dc4b9fd..731b8b0bb 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -204,6 +204,7 @@ namespace command_line extern const arg_descriptor<bool> arg_version; extern const arg_descriptor<std::string> arg_data_dir; extern const arg_descriptor<std::string> arg_testnet_data_dir; + extern const arg_descriptor<std::string> arg_user_agent; extern const arg_descriptor<bool> arg_test_drop_download; extern const arg_descriptor<uint64_t> arg_test_drop_download_height; extern const arg_descriptor<int> arg_test_dbg_lock_sleep; diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 338384cba..9d83caca8 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -74,6 +74,11 @@ monero_add_library(crypto ${crypto_sources} ${crypto_headers} ${crypto_private_headers}) +target_link_libraries(crypto + PUBLIC + ${Boost_SYSTEM_LIBRARY} + PRIVATE + ${EXTRA_LIBRARIES}) if (ARM) option(NO_OPTIMIZED_MULTIPLY_ON_ARM diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 90fda3470..2ac303a36 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -939,7 +939,6 @@ void cn_slow_hash(const void *data, size_t length, char *hash) // ND: Some minor optimizations for ARMv7 (raspberrry pi 2), effect seems to be ~40-50% faster. // Needs more work. -#include "aesb.c" #ifdef NO_OPTIMIZED_MULTIPLY_ON_ARM /* The asm corresponds to this C code */ diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 7c60bcdee..3b676e8ce 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -73,7 +73,7 @@ monero_add_library(cryptonote_core ${cryptonote_core_headers} ${cryptonote_core_private_headers}) target_link_libraries(cryptonote_core - LINK_PUBLIC + PUBLIC common crypto otshell_utils @@ -82,9 +82,9 @@ target_link_libraries(cryptonote_core ${Boost_DATE_TIME_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} - LINK_PRIVATE - ${Blocks} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} + PRIVATE + ${Blocks} ${EXTRA_LIBRARIES}) diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 83e6e40b0..badb1a335 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -85,6 +85,12 @@ static const struct { // version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21. { 3, 1141317, 0, 1458558528 }, + + // version 4 starts from block 1220517, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18. + { 4, 1220517, 0, 1483574400 }, + + // version 5 starts from block 1406997, which is on or around the 20th of September, 2017. Fork time finalised on 2016-09-18. + { 5, 1406997, 0, 1505865600 }, }; static const uint64_t mainnet_hard_fork_version_1_till = 1009826; @@ -100,6 +106,7 @@ static const struct { // version 2 starts from block 624634, which is on or around the 23rd of November, 2015. Fork time finalised on 2015-11-20. No fork voting occurs for the v2 fork. { 2, 624634, 0, 1445355000 }, + // versions 3-5 were passed in rapid succession from September 18th, 2016 { 3, 800500, 0, 1472415034 }, { 4, 801220, 0, 1472415035 }, { 5, 802660, 0, 1472415036 }, diff --git a/src/cryptonote_core/checkpoints.cpp b/src/cryptonote_core/checkpoints.cpp index c038a4802..1d5959c46 100644 --- a/src/cryptonote_core/checkpoints.cpp +++ b/src/cryptonote_core/checkpoints.cpp @@ -184,6 +184,8 @@ namespace cryptonote ADD_CHECKPOINT(825000, "56503f9ad766774b575be3aff73245e9d159be88132c93d1754764f28da2ff60"); ADD_CHECKPOINT(900000, "d9958d0e7dcf91a5a7b11de225927bf7efc6eb26240315ce12372be902cc1337"); ADD_CHECKPOINT(913193, "5292d5d56f6ba4de33a58d9a34d263e2cb3c6fee0aed2286fd4ac7f36d53c85f"); + ADD_CHECKPOINT(1000000, "a886ef5149902d8342475fee9bb296341b891ac67c4842f47a833f23c00ed721"); + ADD_CHECKPOINT(1100000, "3fd720c5c8b3072fc1ccda922dec1ef25f9ed88a1e6ad4103d0fe00b180a5903"); return true; } diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index bad3f30bd..ec717a13d 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -391,7 +391,8 @@ namespace cryptonote }else { //success update, lets update config - epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME); + if (!m_config_folder_path.empty()) + epee::serialization::store_t_to_json_file(m_config, m_config_folder_path + "/" + MINER_CONFIG_FILE_NAME); } } nonce+=m_threads_total; diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt index 6b7d6f79c..11d2d4e3b 100644 --- a/src/cryptonote_protocol/CMakeLists.txt +++ b/src/cryptonote_protocol/CMakeLists.txt @@ -27,7 +27,7 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. cmake_minimum_required (VERSION 2.6) -project (monero CXX) +project (bitmonero CXX) file(GLOB CRYPTONOTE_PROTOCOL *) source_group(cryptonote_protocol FILES ${CRYPTONOTE_PROTOCOL}) diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 90c0299fe..0f4baf932 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -83,7 +83,7 @@ monero_add_executable(daemon ${blocksdat} ) target_link_libraries(daemon - LINK_PRIVATE + PRIVATE rpc blockchain_db cryptonote_core @@ -98,9 +98,7 @@ target_link_libraries(daemon ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_REGEX_LIBRARY} ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} - ${UPNP_LIBRARIES} ${EXTRA_LIBRARIES}) add_dependencies(daemon version) set_property(TARGET daemon diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 00ea6ef6c..83892c661 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -34,10 +34,11 @@ namespace daemonize { t_command_parser_executor::t_command_parser_executor( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) - : m_executor(ip, port, is_rpc, rpc_server) + : m_executor(ip, port, user_agent, is_rpc, rpc_server) {} bool t_command_parser_executor::print_peer_list(const std::vector<std::string>& args) diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 11df92a5e..e59f51cdb 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -49,6 +49,7 @@ public: t_command_parser_executor( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index ce8ac44fc..2c3c54841 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -37,10 +37,11 @@ namespace p = std::placeholders; t_command_server::t_command_server( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) - : m_parser(ip, port, is_rpc, rpc_server) + : m_parser(ip, port, user_agent, is_rpc, rpc_server) , m_command_lookup() , m_is_rpc(is_rpc) { diff --git a/src/daemon/command_server.h b/src/daemon/command_server.h index d7022e135..fb1702aae 100644 --- a/src/daemon/command_server.h +++ b/src/daemon/command_server.h @@ -54,6 +54,7 @@ public: t_command_server( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc = true , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index e79823d08..74875bfb0 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -124,7 +124,7 @@ bool t_daemon::run(bool interactive) if (interactive) { - rpc_commands = new daemonize::t_command_server(0, 0, false, mp_internals->rpc.get_server()); + rpc_commands = new daemonize::t_command_server(0, 0, "", false, mp_internals->rpc.get_server()); rpc_commands->start_handling(std::bind(&daemonize::t_daemon::stop_p2p, this)); } diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 2e8953af9..0895e1bf1 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -208,6 +208,7 @@ int main(int argc, char const * argv[]) { rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_testnet_rpc_bind_port); } + auto user_agent = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_user_agent); uint32_t rpc_ip; uint16_t rpc_port; @@ -222,7 +223,7 @@ int main(int argc, char const * argv[]) return 1; } - daemonize::t_command_server rpc_commands{rpc_ip, rpc_port}; + daemonize::t_command_server rpc_commands{rpc_ip, rpc_port, user_agent}; if (rpc_commands.process_command_vec(command)) { return 0; @@ -280,6 +281,9 @@ int main(int argc, char const * argv[]) if (command_line::has_arg(vm, daemon_args::arg_max_concurrency)) tools::set_max_concurrency(command_line::get_arg(vm, daemon_args::arg_max_concurrency)); + // logging is now set up + LOG_PRINT_L0("Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")"); + _note_c("dbg/main", "Moving from main() into the daemonize now."); return daemonizer::daemonize(argc, argv, daemonize::t_executor{}, vm); diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index b43e01e1f..ad6041fca 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -92,6 +92,7 @@ namespace { t_rpc_command_executor::t_rpc_command_executor( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc , cryptonote::core_rpc_server* rpc_server ) diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 7e73e7faf..afb2b5f36 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -57,6 +57,7 @@ public: t_rpc_command_executor( uint32_t ip , uint16_t port + , const std::string &user_agent , bool is_rpc = true , cryptonote::core_rpc_server* rpc_server = NULL ); diff --git a/src/daemonizer/CMakeLists.txt b/src/daemonizer/CMakeLists.txt index 778f4e4e6..964c8cc6f 100644 --- a/src/daemonizer/CMakeLists.txt +++ b/src/daemonizer/CMakeLists.txt @@ -61,14 +61,10 @@ monero_add_library(daemonizer ${daemonizer_headers} ${daemonizer_private_headers}) target_link_libraries(daemonizer - LINK_PRIVATE + PUBLIC common ${Boost_CHRONO_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} - ${CMAKE_THREAD_LIBS_INIT} - ${UPNP_LIBRARIES} + PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt index cef406c0a..936c43b99 100644 --- a/src/mnemonics/CMakeLists.txt +++ b/src/mnemonics/CMakeLists.txt @@ -51,5 +51,5 @@ monero_add_library(mnemonics ${mnemonics_headers} ${mnemonics_private_headers}) target_link_libraries(mnemonics - LINK_PRIVATE - ${Boost_SYSTEM_LIBRARY}) + PRIVATE + ${EXTRA_LIBRARIES}) diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt index 7f240ab1a..b5b7d87ff 100644 --- a/src/p2p/CMakeLists.txt +++ b/src/p2p/CMakeLists.txt @@ -36,12 +36,15 @@ source_group(p2p FILES ${P2P}) #monero_private_headers(p2p ${P2P}) monero_add_library(p2p ${P2P}) -#target_link_libraries(p2p) -# LINK_PRIVATE -# ${Boost_CHRONO_LIBRARY} -# ${Boost_REGEX_LIBRARY} -# ${Boost_SYSTEM_LIBRARY} -# ${Boost_THREAD_LIBRARY} -# ${EXTRA_LIBRARIES}) +target_link_libraries(p2p + PUBLIC + ${UPNP_LIBRARIES} + ${Boost_CHRONO_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_SYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} + PRIVATE + ${EXTRA_LIBRARIES}) add_dependencies(p2p version) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 75cc8b65a..9c1d8629d 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -360,10 +360,9 @@ namespace nodetool if (testnet) { memcpy(&m_network_id, &::config::testnet::NETWORK_ID, 16); - full_addrs.insert("197.242.158.240:28080"); - full_addrs.insert("107.152.130.98:28080"); - full_addrs.insert("5.9.25.103:28080"); - full_addrs.insert("5.9.55.70:28080"); + full_addrs.insert("163.172.182.165:28080"); + full_addrs.insert("204.12.248.66:28080"); + full_addrs.insert("5.9.100.248:28080"); } else { @@ -439,28 +438,11 @@ namespace nodetool if (!full_addrs.size()) { LOG_PRINT_L0("DNS seed node lookup either timed out or failed, falling back to defaults"); - full_addrs.insert("46.165.232.77:18080"); - full_addrs.insert("63.141.254.186:18080"); - full_addrs.insert("119.81.118.164:18080"); - full_addrs.insert("60.191.33.112:18080"); full_addrs.insert("198.74.231.92:18080"); - full_addrs.insert("5.9.55.70:18080"); - full_addrs.insert("119.81.118.165:18080"); - full_addrs.insert("202.112.0.100:18080"); - full_addrs.insert("84.106.163.174:18080"); - full_addrs.insert("178.206.94.87:18080"); - full_addrs.insert("119.81.118.163:18080"); - full_addrs.insert("95.37.217.253:18080"); full_addrs.insert("161.67.132.39:18080"); - full_addrs.insert("119.81.48.114:18080"); - full_addrs.insert("119.81.118.166:18080"); - full_addrs.insert("93.120.240.209:18080"); - full_addrs.insert("46.183.145.69:18080"); - full_addrs.insert("108.170.123.66:18080"); - full_addrs.insert("5.9.83.204:18080"); - full_addrs.insert("104.130.19.193:18080"); - full_addrs.insert("119.81.48.115:18080"); - full_addrs.insert("80.71.13.36:18080"); + full_addrs.insert("163.172.182.165:18080"); + full_addrs.insert("204.12.248.66:18080"); + full_addrs.insert("5.9.100.248:18080"); } } diff --git a/src/ringct/CMakeLists.txt b/src/ringct/CMakeLists.txt index 594b53b95..334a7f350 100644 --- a/src/ringct/CMakeLists.txt +++ b/src/ringct/CMakeLists.txt @@ -46,14 +46,8 @@ monero_add_library(ringct ${ringct_headers} ${ringct_private_headers}) target_link_libraries(ringct - LINK_PUBLIC + PUBLIC common crypto - ${Boost_DATE_TIME_LIBRARY} - ${Boost_PROGRAM_OPTIONS_LIBRARY} - ${Boost_SERIALIZATION_LIBRARY} - LINK_PRIVATE - ${Boost_FILESYSTEM_LIBRARY} - ${Boost_SYSTEM_LIBRARY} - ${Boost_THREAD_LIBRARY} + PRIVATE ${EXTRA_LIBRARIES}) diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 2e57e62a2..050b5e569 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -43,13 +43,11 @@ monero_add_library(rpc ${rpc_headers} ${rpc_private_headers}) target_link_libraries(rpc - LINK_PRIVATE + PUBLIC cryptonote_core cryptonote_protocol - ${Boost_CHRONO_LIBRARY} - ${Boost_REGEX_LIBRARY} - ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} + PRIVATE ${EXTRA_LIBRARIES}) add_dependencies(rpc version) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 5aa3591ab..f6431a018 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -54,6 +54,7 @@ namespace cryptonote command_line::add_arg(desc, arg_rpc_bind_port); command_line::add_arg(desc, arg_testnet_rpc_bind_port); command_line::add_arg(desc, arg_restricted_rpc); + command_line::add_arg(desc, arg_user_agent); } //------------------------------------------------------------------------------------------------------------------------------ core_rpc_server::core_rpc_server( @@ -81,11 +82,12 @@ namespace cryptonote ) { m_testnet = command_line::get_arg(vm, command_line::arg_testnet_on); + std::string m_user_agent = command_line::get_arg(vm, command_line::arg_user_agent); m_net_server.set_threads_prefix("RPC"); bool r = handle_command_line(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); - return epee::http_server_impl_base<core_rpc_server, connection_context>::init(m_port, m_bind_ip); + return epee::http_server_impl_base<core_rpc_server, connection_context>::init(m_port, m_bind_ip, m_user_agent); } //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::check_core_busy() @@ -1277,4 +1279,10 @@ namespace cryptonote , false }; + const command_line::arg_descriptor<std::string> core_rpc_server::arg_user_agent = { + "user-agent" + , "Restrict RPC to clients using this user agent" + , "" + }; + } // namespace cryptonote diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 9fcf3abf8..9885aa0ff 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -56,6 +56,7 @@ namespace cryptonote static const command_line::arg_descriptor<std::string> arg_rpc_bind_port; static const command_line::arg_descriptor<std::string> arg_testnet_rpc_bind_port; static const command_line::arg_descriptor<bool> arg_restricted_rpc; + static const command_line::arg_descriptor<std::string> arg_user_agent; typedef epee::net_utils::connection_context_base connection_context; diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 1e34d608f..cb9ba2b7c 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -43,7 +43,7 @@ monero_add_executable(simplewallet ${simplewallet_headers} ${simplewallet_private_headers}) target_link_libraries(simplewallet - LINK_PRIVATE + PRIVATE wallet rpc cryptonote_core @@ -51,8 +51,10 @@ target_link_libraries(simplewallet common mnemonics p2p - ${UNBOUND_LIBRARY} - ${UPNP_LIBRARIES} + ${Boost_CHRONO_LIBRARY} + ${Boost_PROGRAM_OPTIONS_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} + ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) add_dependencies(simplewallet diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 421d1f53a..279a5fa41 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -502,10 +502,10 @@ bool simple_wallet::set_default_mixin(const std::vector<std::string> &args/* = s } } -bool simple_wallet::set_default_fee_multiplier(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +bool simple_wallet::set_default_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { bool success = false; - int fee_multiplier = 0; + int priority = 0; if (m_wallet->watch_only()) { fail_msg_writer() << tr("wallet is watch-only and cannot transfer"); @@ -515,19 +515,19 @@ bool simple_wallet::set_default_fee_multiplier(const std::vector<std::string> &a { if (strchr(args[1].c_str(), '-')) { - fail_msg_writer() << tr("fee multiplier must be 0, 1, 2, or 3 "); + fail_msg_writer() << tr("priority must be 0, 1, 2, or 3 "); return true; } if (args[1] == "0") { - fee_multiplier = 0; + priority = 0; } else { - fee_multiplier = boost::lexical_cast<int>(args[1]); - if (fee_multiplier != 1 && fee_multiplier != 2 && fee_multiplier != 3) + priority = boost::lexical_cast<int>(args[1]); + if (priority != 1 && priority != 2 && priority != 3) { - fail_msg_writer() << tr("fee multiplier must be 0, 1, 2, or 3"); + fail_msg_writer() << tr("priority must be 0, 1, 2, or 3"); return true; } } @@ -548,18 +548,18 @@ bool simple_wallet::set_default_fee_multiplier(const std::vector<std::string> &a return true; } - m_wallet->set_default_fee_multiplier(fee_multiplier); + m_wallet->set_default_priority(priority); m_wallet->rewrite(m_wallet_file, pwd_container.password()); return true; } catch(const boost::bad_lexical_cast &) { - fail_msg_writer() << tr("fee multiplier must be 0, 1, 2 or 3"); + fail_msg_writer() << tr("priority must be 0, 1, 2 or 3"); return true; } catch(...) { - fail_msg_writer() << tr("could not change default fee multiplier"); + fail_msg_writer() << tr("could not change default priority"); return true; } } @@ -662,7 +662,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), tr("Display private view key")); m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Display private spend key")); m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Display Electrum-style mnemonic seed")); - m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin <n> - set default mixin (default default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; fee-multiplier [1|2|3] - normal/elevated/priority fee")); + m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("Available options: seed language - set wallet seed language; always-confirm-transfers <1|0> - whether to confirm unsplit txes; store-tx-info <1|0> - whether to store outgoing tx info (destination address, payment ID, tx secret key) for future reference; default-mixin <n> - set default mixin (default is 4); auto-refresh <1|0> - whether to automatically sync new blocks from the daemon; refresh-type <full|optimize-coinbase|no-coinbase|default> - set wallet refresh behaviour; priority [1|2|3] - normal/elevated/priority fee")); m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), tr("Get transaction key (r) for a given <txid>")); m_cmd_binder.set_handler("check_tx_key", boost::bind(&simple_wallet::check_tx_key, this, _1), tr("Check amount going to <address> in <txid>")); @@ -688,7 +688,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) success_msg_writer() << "default-mixin = " << m_wallet->default_mixin(); success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh(); success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type()); - success_msg_writer() << "fee-multiplier = " << m_wallet->get_default_fee_multiplier(); + success_msg_writer() << "priority = " << m_wallet->get_default_priority(); return true; } else @@ -784,18 +784,18 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) return true; } } - else if (args[0] == "fee-multiplier") + else if (args[0] == "priority") { if (args.size() <= 1) { - fail_msg_writer() << tr("set fee-multiplier: needs an argument: 0, 1, 2, or 3"); + fail_msg_writer() << tr("set priority: needs an argument: 0, 1, 2, or 3"); return true; } else { std::vector<std::string> local_args = args; local_args.erase(local_args.begin(), local_args.begin()+2); - set_default_fee_multiplier(local_args); + set_default_priority(local_args); return true; } } @@ -2484,11 +2484,12 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % print_money(e.available()) % print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % - print_money(e.fee()); + print_money(e.fee())); + fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { @@ -2645,12 +2646,12 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee).\n%s")) % + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % print_money(e.available()) % - print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % - print_money(e.fee()) % - tr("This is usually due to dust which is so small it cannot pay for itself in fees"); + print_money(e.fee())); + fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { @@ -2877,12 +2878,12 @@ bool simple_wallet::sweep_all(const std::vector<std::string> &args_) } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee).\n%s")) % + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % print_money(e.available()) % - print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount() + e.fee()) % print_money(e.tx_amount()) % - print_money(e.fee()) % - tr("This is usually due to dust which is so small it cannot pay for itself in fees"); + print_money(e.fee())); + fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees"); } catch (const tools::error::not_enough_outs_to_mix& e) { @@ -3305,7 +3306,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_) for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { const tools::wallet2::unconfirmed_transfer_details &pd = i->second; uint64_t amount = pd.m_amount_in; - uint64_t fee = amount - pd.m_amount_out; + uint64_t fee = amount - pd.m_amount_out - pd.m_change; std::string payment_id = string_tools::pod_to_hex(i->second.m_payment_id); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 1259b95b0..6eb18ed9a 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -143,7 +143,7 @@ namespace cryptonote bool set_tx_note(const std::vector<std::string> &args); bool get_tx_note(const std::vector<std::string> &args); bool status(const std::vector<std::string> &args); - bool set_default_fee_multiplier(const std::vector<std::string> &args); + bool set_default_priority(const std::vector<std::string> &args); bool sign(const std::vector<std::string> &args); bool verify(const std::vector<std::string> &args); bool export_key_images(const std::vector<std::string> &args); diff --git a/src/version.cmake b/src/version.cmake index 8c56b392c..d60673ae2 100644 --- a/src/version.cmake +++ b/src/version.cmake @@ -41,43 +41,23 @@ else() message(STATUS "You are currently on commit ${COMMIT}") # Get all the tags - execute_process(COMMAND "${GIT}" show-ref --tags -d --abbrev RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMITOUT OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND "${GIT}" rev-list --tags --max-count=1 --abbrev-commit RESULT_VARIABLE RET OUTPUT_VARIABLE TAGGEDCOMMIT OUTPUT_STRIP_TRAILING_WHITESPACE) - # Make sure we actually got some tags - if(TAGGEDCOMMITOUT) - string(LENGTH ${TAGGEDCOMMITOUT} TLEN) - else() - set(TLEN 1) - endif() - - if(RET OR TLEN LESS 5) - message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") - set(VERSIONTAG "${COMMIT}") - else() - # Replace a bunch of things so we end up with a semi-colon separated list - string(REPLACE " refs/" "\n" TAGGEDCOMMITOUT2 ${TAGGEDCOMMITOUT}) - string(REPLACE "\n" ";" TAGGEDCOMMITLIST ${TAGGEDCOMMITOUT2}) - - # Grab the second-last item in the list, as that will be the hash of our most recent commit - list(GET TAGGEDCOMMITLIST -2 TAGGEDCOMMIT) - - if(NOT TAGGEDCOMMIT) - message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") - set(VERSIONTAG "${COMMIT}") - else() - message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") - - # Check if we're building that tagged commit or a different one - if(COMMIT STREQUAL TAGGEDCOMMIT) - message(STATUS "You are building a tagged release") - set(VERSIONTAG "release") - else() - message(STATUS "You are ahead of or behind a tagged release") - set(VERSIONTAG "${COMMIT}") - endif() - endif() - - endif() + if(NOT TAGGEDCOMMIT) + message(WARNING "Cannot determine most recent tag. Make sure that you are building either from a Git working tree or from a source archive.") + set(VERSIONTAG "${COMMIT}") + else() + message(STATUS "The most recent tag was at ${TAGGEDCOMMIT}") + + # Check if we're building that tagged commit or a different one + if(COMMIT STREQUAL TAGGEDCOMMIT) + message(STATUS "You are building a tagged release") + set(VERSIONTAG "release") + else() + message(STATUS "You are ahead of or behind a tagged release") + set(VERSIONTAG "${COMMIT}") + endif() + endif() configure_file("src/version.h.in" "${TO}") endif() diff --git a/src/version.h.in b/src/version.h.in index 65b899ed2..c1eca54b8 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define MONERO_VERSION_TAG "@VERSIONTAG@" -#define MONERO_VERSION "0.9.4.0" -#define MONERO_RELEASE_NAME "Hydrogen Helix" +#define MONERO_VERSION "0.10.0.0" +#define MONERO_RELEASE_NAME "Wolfram Warptangent" #define MONERO_VERSION_FULL MONERO_VERSION "-" MONERO_VERSION_TAG diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index cdc460a50..4f82b3c82 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -64,17 +64,19 @@ monero_add_library(wallet ${wallet_api_headers} ${wallet_private_headers}) target_link_libraries(wallet - LINK_PUBLIC + PUBLIC cryptonote_core mnemonics - LINK_PRIVATE + p2p + ${Boost_CHRONO_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} + ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_REGEX_LIBRARY} + PRIVATE ${EXTRA_LIBRARIES}) - # build and install libwallet_merged only if we building for GUI if (BUILD_GUI_DEPS) set(libs_to_merge wallet cryptonote_core mnemonics common crypto ringct) diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index f8704fde3..49ccceb13 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -169,8 +169,10 @@ WalletImpl::WalletImpl(bool testnet) m_wallet->callback(m_wallet2Callback); m_refreshThreadDone = false; m_refreshEnabled = false; + m_refreshIntervalSeconds = DEFAULT_REFRESH_INTERVAL_SECONDS; - m_refreshThread = std::thread([this] () { + + m_refreshThread = boost::thread([this] () { this->refreshThreadFunc(); }); @@ -272,14 +274,15 @@ bool WalletImpl::close() { bool result = false; + LOG_PRINT_L3("closing wallet..."); try { // do not store wallet with invalid status if (status() == Status_Ok) m_wallet->store(); - // LOG_PRINT_L0("wallet::store done"); - // LOG_PRINT_L0("Calling wallet::stop..."); + LOG_PRINT_L3("wallet::store done"); + LOG_PRINT_L3("Calling wallet::stop..."); m_wallet->stop(); - // LOG_PRINT_L0("wallet::stop done"); + LOG_PRINT_L3("wallet::stop done"); result = true; clearStatus(); } catch (const std::exception &e) { @@ -425,6 +428,16 @@ void WalletImpl::refreshAsync() m_refreshCV.notify_one(); } +void WalletImpl::setAutoRefreshInterval(int seconds) +{ + m_refreshIntervalSeconds = seconds; +} + +int WalletImpl::autoRefreshInterval() const +{ + return m_refreshIntervalSeconds; +} + // TODO: // 1 - properly handle payment id (add another menthod with explicit 'payment_id' param) // 2 - check / design how "Transaction" can be single interface @@ -493,9 +506,8 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const //std::vector<tools::wallet2::pending_tx> ptx_vector; try { - // priority called "fee_multiplied in terms of underlying wallet interface transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, - static_cast<uint64_t>(priority), + static_cast<uint32_t>(priority), extra, m_trustedDaemon); } catch (const tools::error::daemon_busy&) { @@ -633,12 +645,20 @@ void WalletImpl::refreshThreadFunc() LOG_PRINT_L3(__FUNCTION__ << ": starting refresh thread"); while (true) { - std::unique_lock<std::mutex> lock(m_refreshMutex); + boost::mutex::scoped_lock lock(m_refreshMutex); if (m_refreshThreadDone) { break; } LOG_PRINT_L3(__FUNCTION__ << ": waiting for refresh..."); - m_refreshCV.wait_for(lock, std::chrono::seconds(m_refreshIntervalSeconds)); + // if auto refresh enabled, we wait for the "m_refreshIntervalSeconds" interval. + // if not - we wait forever + if (m_refreshIntervalSeconds > 0) { + boost::posix_time::milliseconds wait_for_ms(m_refreshIntervalSeconds * 1000); + m_refreshCV.timed_wait(lock, wait_for_ms); + } else { + m_refreshCV.wait(lock); + } + LOG_PRINT_L3(__FUNCTION__ << ": refresh lock acquired..."); LOG_PRINT_L3(__FUNCTION__ << ": m_refreshEnabled: " << m_refreshEnabled); LOG_PRINT_L3(__FUNCTION__ << ": m_status: " << m_status); @@ -653,7 +673,7 @@ void WalletImpl::refreshThreadFunc() void WalletImpl::doRefresh() { // synchronizing async and sync refresh calls - std::lock_guard<std::mutex> guarg(m_refreshMutex2); + boost::lock_guard<boost::mutex> guarg(m_refreshMutex2); try { m_wallet->refresh(); } catch (const std::exception &e) { @@ -681,6 +701,7 @@ void WalletImpl::stopRefresh() if (!m_refreshThreadDone) { m_refreshEnabled = false; m_refreshThreadDone = true; + m_refreshCV.notify_one(); m_refreshThread.join(); } } diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index 9a290e0bc..11880d555 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -35,9 +35,9 @@ #include "wallet/wallet2.h" #include <string> -#include <thread> -#include <mutex> -#include <condition_variable> +#include <boost/thread/mutex.hpp> +#include <boost/thread/thread.hpp> +#include <boost/thread/condition_variable.hpp> namespace Bitmonero { @@ -77,6 +77,11 @@ public: uint64_t unlockedBalance() const; bool refresh(); void refreshAsync(); + void setAutoRefreshInterval(int seconds); + int autoRefreshInterval() const; + + + PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, uint64_t amount, uint32_t mixin_count, PendingTransaction::Priority priority = PendingTransaction::Priority_Low); @@ -113,12 +118,12 @@ private: std::atomic<bool> m_refreshThreadDone; std::atomic<int> m_refreshIntervalSeconds; // synchronizing refresh loop; - std::mutex m_refreshMutex; + boost::mutex m_refreshMutex; // synchronizing sync and async refresh - std::mutex m_refreshMutex2; - std::condition_variable m_refreshCV; - std::thread m_refreshThread; + boost::mutex m_refreshMutex2; + boost::condition_variable m_refreshCV; + boost::thread m_refreshThread; }; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 75d532432..3d4f93aff 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -100,7 +100,6 @@ void do_prepare_file_names(const std::string& file_path, std::string& keys_file, uint64_t calculate_fee(uint64_t fee_per_kb, size_t bytes, uint64_t fee_multiplier) { - THROW_WALLET_EXCEPTION_IF(fee_multiplier <= 0 || fee_multiplier > 3, tools::error::invalid_fee_multiplier); uint64_t kB = (bytes + 1023) / 1024; return kB * fee_per_kb * fee_multiplier; } @@ -1402,8 +1401,8 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p value2.SetUint(m_default_mixin); json.AddMember("default_mixin", value2, json.GetAllocator()); - value2.SetUint(m_default_fee_multiplier); - json.AddMember("default_fee_multiplier", value2, json.GetAllocator()); + value2.SetUint(m_default_priority); + json.AddMember("default_priority", value2, json.GetAllocator()); value2.SetInt(m_auto_refresh ? 1 :0); json.AddMember("auto_refresh", value2, json.GetAllocator()); @@ -1476,7 +1475,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_watch_only = false; m_always_confirm_transfers = false; m_default_mixin = 0; - m_default_fee_multiplier = 0; + m_default_priority = 0; m_auto_refresh = true; m_refresh_type = RefreshType::RefreshDefault; } @@ -1509,8 +1508,19 @@ bool wallet2::load_keys(const std::string& keys_file_name, const std::string& pa m_store_tx_info = ((field_store_tx_keys != 0) || (field_store_tx_info != 0)); GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_mixin, unsigned int, Uint, false, 0); m_default_mixin = field_default_mixin; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_fee_multiplier, unsigned int, Uint, false, 0); - m_default_fee_multiplier = field_default_fee_multiplier; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_priority, unsigned int, Uint, false, 0); + if (field_default_priority_found) + { + m_default_priority = field_default_priority; + } + else + { + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, default_fee_multiplier, unsigned int, Uint, false, 0); + if (field_default_fee_multiplier_found) + m_default_priority = field_default_fee_multiplier; + else + m_default_priority = 0; + } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_refresh, int, Int, false, true); m_auto_refresh = field_auto_refresh; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_type, int, Int, false, RefreshType::RefreshDefault); @@ -2535,15 +2545,22 @@ void wallet2::commit_tx(std::vector<pending_tx>& ptx_vector) } } -uint64_t wallet2::sanitize_fee_multiplier(uint64_t fee_multiplier) const +uint64_t wallet2::get_fee_multiplier(uint32_t priority, bool use_new_fee) const { - // 0, default value used for previous fee argument, defaults to normal fee - if (fee_multiplier == 0) - return m_default_fee_multiplier > 0 ? m_default_fee_multiplier : 1; - // 1 to 3 are allowed as multipliers - if (fee_multiplier >= 1 && fee_multiplier <= 3) - return fee_multiplier; - THROW_WALLET_EXCEPTION_IF (false, error::invalid_fee_multiplier); + static const uint64_t old_multipliers[3] = {1, 2, 3}; + static const uint64_t new_multipliers[3] = {1, 20, 166}; + + // 0 -> default (here, x1) + if (priority == 0) + priority = m_default_priority; + if (priority == 0) + priority = 1; + + // 1 to 3 are allowed as priorities + if (priority >= 1 && priority <= 3) + return (use_new_fee ? new_multipliers : old_multipliers)[priority-1]; + + THROW_WALLET_EXCEPTION_IF (false, error::invalid_priority); return 1; } @@ -2552,12 +2569,13 @@ uint64_t wallet2::sanitize_fee_multiplier(uint64_t fee_multiplier) const // // this function will make multiple calls to wallet2::transfer if multiple // transactions will be required -std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon) +std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon) { const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, trusted_daemon); - const uint64_t fee_per_kb = use_fork_rules(3, -720 * 14) ? FEE_PER_KB : FEE_PER_KB_OLD; - fee_multiplier = sanitize_fee_multiplier(fee_multiplier); + const bool use_new_fee = use_fork_rules(3, -720 * 14); + const uint64_t fee_per_kb = use_new_fee ? FEE_PER_KB : FEE_PER_KB_OLD; + const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee); // failsafe split attempt counter size_t attempt_count = 0; @@ -3045,16 +3063,18 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry ++out_index; } + // we still keep a copy, since we want to keep dsts free of change for user feedback purposes + std::vector<cryptonote::tx_destination_entry> splitted_dsts = dsts; cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts); if (needed_money < found_money) { change_dts.addr = m_account.get_keys().m_account_address; change_dts.amount = found_money - needed_money; - dsts.push_back(change_dts); + splitted_dsts.push_back(change_dts); } crypto::secret_key tx_key; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, dsts, extra, tx, unlock_time, tx_key, true); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, true); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_testnet); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -3198,7 +3218,7 @@ std::vector<size_t> wallet2::pick_prefered_rct_inputs(uint64_t needed_money) con // This system allows for sending (almost) the entire balance, since it does // not generate spurious change in all txes, thus decreasing the instantaneous // usable balance. -std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon) +std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon) { std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_dust_indices; @@ -3226,8 +3246,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit(); const bool use_rct = use_fork_rules(4, 0); - const uint64_t fee_per_kb = use_fork_rules(3, -720 * 14) ? FEE_PER_KB : FEE_PER_KB_OLD; - fee_multiplier = sanitize_fee_multiplier(fee_multiplier); + const bool use_new_fee = use_fork_rules(3, -720 * 14); + const uint64_t fee_per_kb = use_new_fee ? FEE_PER_KB : FEE_PER_KB_OLD; + const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee); // throw if attempting a transaction with no destinations THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); @@ -3260,6 +3281,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp } LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs"); + if (unused_dust_indices.empty() && unused_transfers_indices.empty()) + return std::vector<wallet2::pending_tx>(); + // start with an empty tx txes.push_back(TX()); accumulated_fee = 0; @@ -3461,7 +3485,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp return ptx_vector; } -std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon) +std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon) { std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_dust_indices; @@ -3478,8 +3502,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit(); const bool use_rct = use_fork_rules(4, 0); - const uint64_t fee_per_kb = use_fork_rules(3, -720 * 14) ? FEE_PER_KB : FEE_PER_KB_OLD; - fee_multiplier = sanitize_fee_multiplier(fee_multiplier); + const bool use_new_fee = use_fork_rules(3, -720 * 14); + const uint64_t fee_per_kb = use_new_fee ? FEE_PER_KB : FEE_PER_KB_OLD; + const uint64_t fee_multiplier = get_fee_multiplier(priority, use_new_fee); // gather all our dust and non dust outputs for (size_t i = 0; i < m_transfers.size(); ++i) @@ -3495,6 +3520,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(const cryptono } LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs"); + if (unused_dust_indices.empty() && unused_transfers_indices.empty()) + return std::vector<wallet2::pending_tx>(); + // start with an empty tx txes.push_back(TX()); accumulated_fee = 0; @@ -3893,7 +3921,8 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bo const bool hf1_rules = use_fork_rules(2, 10); // first hard fork has version 2 tx_dust_policy dust_policy(hf1_rules ? 0 : ::config::DEFAULT_DUST_THRESHOLD); - const uint64_t fee_per_kb = use_fork_rules(3, -720 * 14) ? FEE_PER_KB : FEE_PER_KB_OLD; + const bool use_new_fee = use_fork_rules(3, -720 * 14); + const uint64_t fee_per_kb = use_new_fee ? FEE_PER_KB : FEE_PER_KB_OLD; // may throw std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs(trusted_daemon); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 0fc25bf8c..89b613d34 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -92,10 +92,10 @@ namespace tools }; private: - wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_default_fee_multiplier(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} + wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} public: - wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_default_fee_multiplier(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} + wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_restricted(restricted), is_old_file_format(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0) {} struct transfer_details { uint64_t m_block_height; @@ -305,9 +305,9 @@ namespace tools void commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector<pending_tx>& ptx_vector); - std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon); - std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon); - std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector<uint8_t> extra, bool trusted_daemon); + std::vector<pending_tx> create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon); + std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon); + std::vector<wallet2::pending_tx> create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t> extra, bool trusted_daemon); std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon); bool check_connection(bool *same_version = NULL); void get_transfers(wallet2::transfer_container& incoming_transfers) const; @@ -385,8 +385,8 @@ namespace tools void store_tx_info(bool store) { m_store_tx_info = store; } uint32_t default_mixin() const { return m_default_mixin; } void default_mixin(uint32_t m) { m_default_mixin = m; } - uint32_t get_default_fee_multiplier() const { return m_default_fee_multiplier; } - void set_default_fee_multiplier(uint32_t m) { m_default_fee_multiplier = m; } + uint32_t get_default_priority() const { return m_default_priority; } + void set_default_priority(uint32_t p) { m_default_priority = p; } bool auto_refresh() const { return m_auto_refresh; } void auto_refresh(bool r) { m_auto_refresh = r; } @@ -458,7 +458,7 @@ namespace tools void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_tranaction_size_limit(); std::vector<uint64_t> get_unspent_amounts_vector(); - uint64_t sanitize_fee_multiplier(uint64_t fee_multiplier) const; + uint64_t get_fee_multiplier(uint32_t priority, bool use_new_fee) const; float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const; std::vector<size_t> pick_prefered_rct_inputs(uint64_t needed_money) const; void set_spent(transfer_details &td, uint64_t height); @@ -498,7 +498,7 @@ namespace tools bool m_always_confirm_transfers; bool m_store_tx_info; /*!< request txkey to be returned in RPC, and store in the wallet cache file */ uint32_t m_default_mixin; - uint32_t m_default_fee_multiplier; + uint32_t m_default_priority; RefreshType m_refresh_type; bool m_auto_refresh; uint64_t m_refresh_from_block_height; diff --git a/src/wallet/wallet2_api.h b/src/wallet/wallet2_api.h index e880b1c68..2d2877856 100644 --- a/src/wallet/wallet2_api.h +++ b/src/wallet/wallet2_api.h @@ -223,10 +223,25 @@ struct Wallet * @return - true if refreshed successfully; */ virtual bool refresh() = 0; + /** * @brief refreshAsync - refreshes wallet asynchronously. */ virtual void refreshAsync() = 0; + + /** + * @brief setAutoRefreshInterval - setup interval for automatic refresh. + * @param seconds - interval in seconds. if zero or less than zero - automatic refresh disabled; + */ + virtual void setAutoRefreshInterval(int seconds) = 0; + + /** + * @brief autoRefreshInterval - returns automatic refresh interval in seconds + * @return + */ + virtual int autoRefreshInterval() const = 0; + + /*! * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored * \param dst_addr destination address as string diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 8ea061152..c5590d79c 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -56,7 +56,7 @@ namespace tools // file_read_error // file_save_error // invalid_password - // invalid_fee_multiplier + // invalid_priority // refresh_error * // acc_outs_lookup_error // block_parse_error @@ -227,10 +227,10 @@ namespace tools std::string to_string() const { return wallet_logic_error::to_string(); } }; - struct invalid_fee_multiplier : public wallet_logic_error + struct invalid_priority : public wallet_logic_error { - explicit invalid_fee_multiplier(std::string&& loc) - : wallet_logic_error(std::move(loc), "invalid fee multiplier") + explicit invalid_priority(std::string&& loc) + : wallet_logic_error(std::move(loc), "invalid priority") { } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 0e76075d1..faa40e166 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -45,11 +45,13 @@ namespace tools //----------------------------------------------------------------------------------- const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_port = {"rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", "", true}; const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip = {"rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1"}; + const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_user_agent = {"user-agent", "Restrict RPC to clients using this user agent", ""}; void wallet_rpc_server::init_options(boost::program_options::options_description& desc) { command_line::add_arg(desc, arg_rpc_bind_ip); command_line::add_arg(desc, arg_rpc_bind_port); + command_line::add_arg(desc, arg_user_agent); } //------------------------------------------------------------------------------------------------------------------------------ wallet_rpc_server::wallet_rpc_server(wallet2& w):m_wallet(w) @@ -83,6 +85,7 @@ namespace tools { m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip); m_port = command_line::get_arg(vm, arg_rpc_bind_port); + m_user_agent = command_line::get_arg(vm, arg_user_agent); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -91,7 +94,7 @@ namespace tools m_net_server.set_threads_prefix("RPC"); bool r = handle_command_line(vm); CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server"); - return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip); + return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip, m_user_agent); } //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er) @@ -239,7 +242,7 @@ namespace tools LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2"); mixin = 2; } - std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon); // reject proposed transactions if there are more than one. see on_transfer_split below. if (ptx_vector.size() != 1) @@ -307,7 +310,7 @@ namespace tools mixin = 2; } std::vector<wallet2::pending_tx> ptx_vector; - ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon); + ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.trusted_daemon); m_wallet.commit_tx(ptx_vector); @@ -416,7 +419,7 @@ namespace tools try { - std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.fee_multiplier, extra, req.trusted_daemon); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions_all(dsts[0].addr, req.mixin, req.unlock_time, req.priority, extra, req.trusted_daemon); m_wallet.commit_tx(ptx_vector); diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index c2532948f..b3e95c18a 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -50,6 +50,7 @@ namespace tools const static command_line::arg_descriptor<std::string> arg_rpc_bind_port; const static command_line::arg_descriptor<std::string> arg_rpc_bind_ip; + const static command_line::arg_descriptor<std::string> arg_user_agent; static void init_options(boost::program_options::options_description& desc); @@ -120,6 +121,7 @@ namespace tools wallet2& m_wallet; std::string m_port; std::string m_bind_ip; + std::string m_user_agent; std::atomic<bool> m_stop; }; } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 6439a19fe..cde9863a2 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -110,7 +110,7 @@ namespace wallet_rpc struct request { std::list<transfer_destination> destinations; - uint64_t fee_multiplier; + uint32_t priority; uint64_t mixin; uint64_t unlock_time; std::string payment_id; @@ -119,7 +119,7 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) - KV_SERIALIZE(fee_multiplier) + KV_SERIALIZE(priority) KV_SERIALIZE(mixin) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) @@ -147,7 +147,7 @@ namespace wallet_rpc struct request { std::list<transfer_destination> destinations; - uint64_t fee_multiplier; + uint32_t priority; uint64_t mixin; uint64_t unlock_time; std::string payment_id; @@ -156,7 +156,7 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) - KV_SERIALIZE(fee_multiplier) + KV_SERIALIZE(priority) KV_SERIALIZE(mixin) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) @@ -225,7 +225,7 @@ namespace wallet_rpc struct request { std::string address; - uint64_t fee_multiplier; + uint32_t priority; uint64_t mixin; uint64_t unlock_time; std::string payment_id; @@ -234,7 +234,7 @@ namespace wallet_rpc BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(address) - KV_SERIALIZE(fee_multiplier) + KV_SERIALIZE(priority) KV_SERIALIZE(mixin) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) |