diff options
-rw-r--r-- | CMakeLists.txt | 23 | ||||
-rw-r--r-- | src/cryptonote_core/hardfork.cpp | 11 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 107 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.h | 2 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 116 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 4 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 66 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.h | 4 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 65 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_error_codes.h | 1 |
10 files changed, 389 insertions, 10 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 70c0c89f7..0a0e75119 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -295,7 +295,7 @@ link_directories(${LIBUNWIND_LIBRARY_DIRS}) if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(COMMON_C_FLAGS "${COMMON_C_FLAGS} /Dinline=__inline") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760") + set(COMMON_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} /STACK:10485760") if(STATIC) foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}") @@ -333,7 +333,7 @@ else() include_directories(SYSTEM src/platform/mingw) # mingw doesn't support LTO (multiple definition errors at link time) set(USE_LTO_DEFAULT false) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,10485760") + set(COMMON_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} -Wl,--stack,10485760") if(NOT BUILD_64) add_definitions(-DWINVER=0x0501 -D_WIN32_WINNT=0x0501) endif() @@ -420,9 +420,14 @@ else() set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEBUG_FLAGS}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RELEASE_FLAGS}") + if(STATIC AND NOT APPLE AND NOT FREEBSD AND NOT OPENBSD) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--wrap=__cxa_throw") + set(COMMON_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") + endif() + + if(STATIC AND NOT FREEBSD AND NOT OPENBSD) + # Install hook on throw for dumping stack on exception (implemented in libcommon) + set(WRAP_CXA_THROW_FLAG "-Wl,--wrap=__cxa_throw") endif() endif() @@ -471,9 +476,12 @@ endif() include(version.cmake) -# When building the following sources, treat warnings as errors +# When building the following sources... +# ...treat warnings as errors, install throw wrapper set(CMAKE_C_FLAGS "${COMMON_C_FLAGS} ${WARNINGS_AS_ERRORS_FLAG}") set(CMAKE_CXX_FLAGS "${COMMON_CXX_FLAGS} ${WARNINGS_AS_ERRORS_FLAG}") +# ...install hook on throw +set(CMAKE_EXE_LINKER_FLAGS "${COMMON_EXE_LINKER_FLAGS} ${WRAP_CXA_THROW_FLAG}") add_subdirectory(contrib) add_subdirectory(src) @@ -482,9 +490,12 @@ add_subdirectory(src) option(BUILD_TESTS "Build tests." OFF) if(BUILD_TESTS) - # When building tests, do *not* treat warnings as errors + # When building tests... + # ...do *not* treat warnings as errors set(CMAKE_C_FLAGS "${COMMON_C_FLAGS}") set(CMAKE_CXX_FLAGS "${COMMON_CXX_FLAGS}") + # ...do *not* install hook on throw + set(CMAKE_EXE_LINKER_FLAGS "${COMMON_CXX_FLAGS}") add_subdirectory(tests) endif() diff --git a/src/cryptonote_core/hardfork.cpp b/src/cryptonote_core/hardfork.cpp index d3262dbe3..39c026b08 100644 --- a/src/cryptonote_core/hardfork.cpp +++ b/src/cryptonote_core/hardfork.cpp @@ -164,7 +164,7 @@ void HardFork::init() // restore state from DB uint64_t height = db.height(); if (height > window_size) - height -= window_size; + height -= window_size - 1; else height = 1; @@ -259,8 +259,7 @@ bool HardFork::rescan_from_block_height(uint64_t height) for (size_t n = 0; n < 256; ++n) last_versions[n] = 0; - const uint64_t rescan_height = height >= (window_size - 1) ? height - (window_size -1) : 0; - for (uint64_t h = rescan_height; h <= height; ++h) { + for (uint64_t h = height; h < db.height(); ++h) { cryptonote::block b = db.get_block_from_height(h); const uint8_t v = get_effective_version(get_block_vote(b)); last_versions[v]++; @@ -271,6 +270,12 @@ bool HardFork::rescan_from_block_height(uint64_t height) current_fork_index = 0; while (current_fork_index + 1 < heights.size() && heights[current_fork_index].version != lastv) ++current_fork_index; + + uint8_t voted = get_voted_fork_index(db.height()); + if (voted > current_fork_index) { + current_fork_index = voted; + } + db.block_txn_stop(); return true; diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index eb763b0cd..a3a4685b5 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -662,6 +662,8 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("status", boost::bind(&simple_wallet::status, this, _1), tr("Show wallet status information")); m_cmd_binder.set_handler("sign", boost::bind(&simple_wallet::sign, this, _1), tr("Sign the contents of a file")); m_cmd_binder.set_handler("verify", boost::bind(&simple_wallet::verify, this, _1), tr("Verify a signature on the contents of a file")); + m_cmd_binder.set_handler("export_key_images", boost::bind(&simple_wallet::export_key_images, this, _1), tr("Export a signed set of key images")); + m_cmd_binder.set_handler("import_key_images", boost::bind(&simple_wallet::import_key_images, this, _1), tr("Import signed key images list and verify their spent status")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- @@ -3480,6 +3482,111 @@ bool simple_wallet::verify(const std::vector<std::string> &args) return true; } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::export_key_images(const std::vector<std::string> &args) +{ + if (args.size() != 1) + { + fail_msg_writer() << tr("usage: export_key_images <filename>"); + return true; + } + if (m_wallet->watch_only()) + { + fail_msg_writer() << tr("wallet is watch-only and cannot export key images"); + return true; + } + std::string filename = args[0]; + + try + { + std::vector<std::pair<crypto::key_image, crypto::signature>> ski = m_wallet->export_key_images(); + std::string data; + for (const auto &i: ski) + { + data += epee::string_tools::pod_to_hex(i.first); + data += epee::string_tools::pod_to_hex(i.second); + } + bool r = epee::file_io_utils::save_string_to_file(filename, data); + if (!r) + { + fail_msg_writer() << tr("failed to save file ") << filename; + return true; + } + } + catch (std::exception &e) + { + LOG_ERROR("Error exporting key images: " << e.what()); + fail_msg_writer() << "Error exporting key images: " << e.what(); + return true; + } + + success_msg_writer() << tr("Signed key images exported to ") << filename; + return true; +} +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::import_key_images(const std::vector<std::string> &args) +{ + if (args.size() != 1) + { + fail_msg_writer() << tr("usage: import_key_images <filename>"); + return true; + } + std::string filename = args[0]; + + std::string data; + bool r = epee::file_io_utils::load_file_to_string(filename, data); + if (!r) + { + fail_msg_writer() << tr("failed to read file ") << filename; + return true; + } + + const size_t record_size = sizeof(crypto::key_image)*2 + sizeof(crypto::signature)*2; + if (data.size() % record_size) + { + fail_msg_writer() << "Bad data size from file " << filename; + return true; + } + size_t nki = data.size() / record_size; + + std::vector<std::pair<crypto::key_image, crypto::signature>> ski; + ski.reserve(nki); + for (size_t n = 0; n < nki; ++n) + { + cryptonote::blobdata bd; + + if(!epee::string_tools::parse_hexstr_to_binbuff(std::string(&data[n * record_size], sizeof(crypto::key_image)*2), bd)) + { + fail_msg_writer() << tr("failed to parse key image"); + return false; + } + crypto::key_image key_image = *reinterpret_cast<const crypto::key_image*>(bd.data()); + + if(!epee::string_tools::parse_hexstr_to_binbuff(std::string(&data[n * record_size + sizeof(crypto::key_image)*2], sizeof(crypto::signature)*2), bd)) + { + fail_msg_writer() << tr("failed to parse signature"); + return false; + } + crypto::signature signature = *reinterpret_cast<const crypto::signature*>(bd.data()); + + ski.push_back(std::make_pair(key_image, signature)); + } + + try + { + uint64_t spent = 0, unspent = 0; + uint64_t height = m_wallet->import_key_images(ski, spent, unspent); + success_msg_writer() << "Signed key images imported to height " << height << ", " + << print_money(spent) << " spent, " << print_money(unspent) << " unspent"; + } + catch (const std::exception &e) + { + fail_msg_writer() << "Failed to import key images: " << e.what(); + return true; + } + + return true; +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::process_command(const std::vector<std::string> &args) { return m_cmd_binder.process_command_vec(args); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7d8e7730c..b35ca0866 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -145,6 +145,8 @@ namespace cryptonote bool set_default_fee_multiplier(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); + bool import_key_images(const std::vector<std::string> &args); uint64_t get_daemon_blockchain_height(std::string& err); bool try_connect_to_daemon(bool silent = false); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 201f0a1f4..43dedaf82 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3286,7 +3286,123 @@ bool wallet2::verify(const std::string &data, const cryptonote::account_public_a memcpy(&s, decoded.data(), sizeof(s)); return crypto::check_signature(hash, address.m_spend_public_key, s); } +//---------------------------------------------------------------------------------------------------- +std::vector<std::pair<crypto::key_image, crypto::signature>> wallet2::export_key_images() const +{ + std::vector<std::pair<crypto::key_image, crypto::signature>> ski; + + ski.reserve(m_transfers.size()); + for (size_t n = 0; n < m_transfers.size(); ++n) + { + const transfer_details &td = m_transfers[n]; + + crypto::hash hash; + crypto::cn_fast_hash(&td.m_key_image, sizeof(td.m_key_image), hash); + + // get ephemeral public key + const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index]; + THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error, + "Output is not txout_to_key"); + const cryptonote::txout_to_key &o = boost::get<const cryptonote::txout_to_key>(out.target); + const crypto::public_key pkey = o.key; + + // get tx pub key + std::vector<tx_extra_field> tx_extra_fields; + if(!parse_tx_extra(td.m_tx.extra, tx_extra_fields)) + { + // Extra may only be partially parsed, it's OK if tx_extra_fields contains public key + } + tx_extra_pub_key pub_key_field; + THROW_WALLET_EXCEPTION_IF(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field), error::wallet_internal_error, + "Public key wasn't found in the transaction extra"); + crypto::public_key tx_pub_key = pub_key_field.pub_key; + + // generate ephemeral secret key + crypto::key_image ki; + cryptonote::keypair in_ephemeral; + cryptonote::generate_key_image_helper(m_account.get_keys(), tx_pub_key, td.m_internal_output_index, in_ephemeral, ki); + THROW_WALLET_EXCEPTION_IF(ki != td.m_key_image, + error::wallet_internal_error, "key_image generated not matched with cached key image"); + THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != pkey, + error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); + // sign the key image with the output secret key + crypto::signature signature; + std::vector<const crypto::public_key*> key_ptrs; + key_ptrs.push_back(&pkey); + + crypto::generate_ring_signature((const crypto::hash&)td.m_key_image, td.m_key_image, key_ptrs, in_ephemeral.sec, 0, &signature); + + ski.push_back(std::make_pair(td.m_key_image, signature)); + } + return ski; +} +//---------------------------------------------------------------------------------------------------- +uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent) +{ + COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req); + COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + + THROW_WALLET_EXCEPTION_IF(signed_key_images.size() > m_transfers.size(), error::wallet_internal_error, + "The blockchain is out of date compared to the signed key images"); + + if (signed_key_images.empty()) + { + spent = 0; + unspent = 0; + return 0; + } + + for (size_t n = 0; n < signed_key_images.size(); ++n) + { + const transfer_details &td = m_transfers[n]; + const crypto::key_image &key_image = signed_key_images[n].first; + const crypto::signature &signature = signed_key_images[n].second; + + // get ephemeral public key + const cryptonote::tx_out &out = td.m_tx.vout[td.m_internal_output_index]; + THROW_WALLET_EXCEPTION_IF(out.target.type() != typeid(txout_to_key), error::wallet_internal_error, + "Non txout_to_key output found"); + const cryptonote::txout_to_key &o = boost::get<cryptonote::txout_to_key>(out.target); + const crypto::public_key pkey = o.key; + + std::vector<const crypto::public_key*> pkeys; + pkeys.push_back(&pkey); + THROW_WALLET_EXCEPTION_IF(!crypto::check_ring_signature((const crypto::hash&)key_image, key_image, pkeys, &signature), + error::wallet_internal_error, "Signature check failed: key image " + epee::string_tools::pod_to_hex(key_image) + + ", signature " + epee::string_tools::pod_to_hex(signature) + ", pubkey " + epee::string_tools::pod_to_hex(*pkeys[0])); + + req.key_images.push_back(epee::string_tools::pod_to_hex(key_image)); + } + + m_daemon_rpc_mutex.lock(); + bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000); + m_daemon_rpc_mutex.unlock(); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status); + THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error, + "daemon returned wrong response for is_key_image_spent, wrong amounts count = " + + std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size())); + + spent = 0; + unspent = 0; + for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n) + { + transfer_details &td = m_transfers[n]; + uint64_t amount = td.m_tx.vout[td.m_internal_output_index].amount; + td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT; + if (td.m_spent) + spent += amount; + else + unspent += amount; + LOG_PRINT_L2("Transfer " << n << ": " << print_money(amount) << " (" << td.m_global_output_index << "): " + << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[n] << ")"); + } + LOG_PRINT_L1("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent"); + + return m_transfers[signed_key_images.size() - 1].m_block_height; +} //---------------------------------------------------------------------------------------------------- void wallet2::generate_genesis(cryptonote::block& b) { if (m_testnet) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index de3580777..62a3c5031 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -394,8 +394,10 @@ namespace tools std::string sign(const std::string &data) const; bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const; - void update_pool_state(); + std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const; + uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent); + void update_pool_state(); private: /*! * \brief Stores wallet information to wallet file. diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index dbfb880a1..debd7056a 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -995,5 +995,71 @@ namespace tools return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er) + { + try + { + std::vector<std::pair<crypto::key_image, crypto::signature>> ski = m_wallet.export_key_images(); + res.signed_key_images.resize(ski.size()); + for (size_t n = 0; n < ski.size(); ++n) + { + res.signed_key_images[n].key_image = epee::string_tools::pod_to_hex(ski[n].first); + res.signed_key_images[n].signature = epee::string_tools::pod_to_hex(ski[n].second); + } + } + + catch (...) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Failed"; + return false; + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool wallet_rpc_server::on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er) + { + try + { + std::vector<std::pair<crypto::key_image, crypto::signature>> ski; + ski.resize(req.signed_key_images.size()); + for (size_t n = 0; n < ski.size(); ++n) + { + cryptonote::blobdata bd; + + if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].key_image, bd)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE; + er.message = "failed to parse key image"; + return false; + } + ski[n].first = *reinterpret_cast<const crypto::key_image*>(bd.data()); + + if(!epee::string_tools::parse_hexstr_to_binbuff(req.signed_key_images[n].signature, bd)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE; + er.message = "failed to parse signature"; + return false; + } + ski[n].second = *reinterpret_cast<const crypto::signature*>(bd.data()); + } + uint64_t spent = 0, unspent = 0; + uint64_t height = m_wallet.import_key_images(ski, spent, unspent); + res.spent = spent; + res.unspent = unspent; + res.height = height; + } + + catch (...) + { + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Failed"; + return false; + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ } diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index 205896332..c2532948f 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -82,6 +82,8 @@ namespace tools MAP_JON_RPC_WE("get_transfers", on_get_transfers, wallet_rpc::COMMAND_RPC_GET_TRANSFERS) MAP_JON_RPC_WE("sign", on_sign, wallet_rpc::COMMAND_RPC_SIGN) MAP_JON_RPC_WE("verify", on_verify, wallet_rpc::COMMAND_RPC_VERIFY) + MAP_JON_RPC_WE("export_key_images", on_export_key_images, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES) + MAP_JON_RPC_WE("import_key_images", on_import_key_images, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES) END_JSON_RPC_MAP() END_URI_MAP2() @@ -107,6 +109,8 @@ namespace tools bool on_get_transfers(const wallet_rpc::COMMAND_RPC_GET_TRANSFERS::request& req, wallet_rpc::COMMAND_RPC_GET_TRANSFERS::response& res, epee::json_rpc::error& er); bool on_sign(const wallet_rpc::COMMAND_RPC_SIGN::request& req, wallet_rpc::COMMAND_RPC_SIGN::response& res, epee::json_rpc::error& er); bool on_verify(const wallet_rpc::COMMAND_RPC_VERIFY::request& req, wallet_rpc::COMMAND_RPC_VERIFY::response& res, epee::json_rpc::error& er); + bool on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er); + bool on_import_key_images(const wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_IMPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er); bool handle_command_line(const boost::program_options::variables_map& vm); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index f4eefcd1a..d7f01d9ee 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -601,5 +601,70 @@ namespace wallet_rpc }; }; + struct COMMAND_RPC_EXPORT_KEY_IMAGES + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct signed_key_image + { + std::string key_image; + std::string signature; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_image); + KV_SERIALIZE(signature); + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::vector<signed_key_image> signed_key_images; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(signed_key_images); + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_IMPORT_KEY_IMAGES + { + struct signed_key_image + { + std::string key_image; + std::string signature; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_image); + KV_SERIALIZE(signature); + END_KV_SERIALIZE_MAP() + }; + + struct request + { + std::vector<signed_key_image> signed_key_images; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(signed_key_images); + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t height; + uint64_t spent; + uint64_t unspent; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(spent) + KV_SERIALIZE(unspent) + END_KV_SERIALIZE_MAP() + }; + }; + } } diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index 68edfe76e..4617a1449 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -40,3 +40,4 @@ #define WALLET_RPC_ERROR_CODE_DENIED -7 #define WALLET_RPC_ERROR_CODE_WRONG_TXID -8 #define WALLET_RPC_ERROR_CODE_WRONG_SIGNATURE -9 +#define WALLET_RPC_ERROR_CODE_WRONG_KEY_IMAGE -10 |