diff options
Diffstat (limited to 'src/wallet')
-rw-r--r-- | src/wallet/api/address_book.cpp | 2 | ||||
-rw-r--r-- | src/wallet/api/wallet.cpp | 5 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 73 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 11 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 54 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_commands_defs.h | 5 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server_error_codes.h | 6 |
7 files changed, 96 insertions, 60 deletions
diff --git a/src/wallet/api/address_book.cpp b/src/wallet/api/address_book.cpp index 8089a6a05..38c34a912 100644 --- a/src/wallet/api/address_book.cpp +++ b/src/wallet/api/address_book.cpp @@ -74,7 +74,7 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa // integrated + long payment id provided if(has_long_pid && info.has_payment_id) { - m_errorString = tr("Integrated address and long payment id can't be used at the same time"); + m_errorString = tr("Integrated address and long payment ID can't be used at the same time"); m_errorCode = Invalid_Payment_Id; return false; } diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 82948081e..5ce8ede8d 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -626,7 +626,7 @@ bool WalletImpl::close(bool store) if (status() != Status_Critical) m_wallet->store(); else - LOG_ERROR("Status_Critical - not storing wallet"); + LOG_ERROR("Status_Critical - not saving wallet"); LOG_PRINT_L1("wallet::store done"); } LOG_PRINT_L1("Calling wallet::stop..."); @@ -732,7 +732,7 @@ bool WalletImpl::store(const std::string &path) m_wallet->store_to(path, m_password); } } catch (const std::exception &e) { - LOG_ERROR("Error storing wallet: " << e.what()); + LOG_ERROR("Error saving wallet: " << e.what()); m_status = Status_Error; m_errorString = e.what(); } @@ -1198,6 +1198,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const for (const std::pair<uint64_t, uint64_t> outs_for_amount : e.scanty_outs()) { writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second; } + writer << "\n" << tr("Please sweep unmixable outputs."); m_errorString = writer.str(); m_status = Status_Error; } catch (const tools::error::tx_not_constructed&) { diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 7dc8a1e47..3bad743cf 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -223,7 +223,7 @@ boost::optional<tools::password_container> get_password(const boost::program_opt THROW_WALLET_EXCEPTION_IF(!password_prompter, tools::error::wallet_internal_error, tools::wallet2::tr("no password specified; use --prompt-for-password to prompt for a password")); - return password_prompter(verify ? tr("Enter new wallet password") : tr("Wallet password"), verify); + return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify); } std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) @@ -361,6 +361,7 @@ std::unique_ptr<tools::wallet2> generate_from_json(const std::string& json_file, wallet.reset(make_basic(vm, opts, password_prompter).release()); wallet->set_refresh_from_block_height(field_scan_from_height); + wallet->explicit_refresh_from_block_height(field_scan_from_height_found); try { @@ -532,12 +533,9 @@ size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, si return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size; } -uint8_t get_bulletproof_fork(bool testnet) +uint8_t get_bulletproof_fork() { - if (testnet) - return 7; - else - return 255; // TODO + return 8; } crypto::hash8 get_short_payment_id(const tools::wallet2::pending_tx &ptx) @@ -604,6 +602,7 @@ wallet2::wallet2(bool testnet, bool restricted): m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), + m_explicit_refresh_from_block_height(true), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), @@ -889,14 +888,12 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) cryptonote::subaddress_index index2; for (index2.major = m_subaddress_labels.size(); index2.major < index.major + m_subaddress_lookahead_major; ++index2.major) { - for (index2.minor = 0; index2.minor < (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor; ++index2.minor) + const uint32_t end = (index2.major == index.major ? index.minor : 0) + m_subaddress_lookahead_minor; + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, 0, end); + for (index2.minor = 0; index2.minor < end; ++index2.minor) { - if (m_subaddresses_inv.count(index2) == 0) - { - crypto::public_key D = get_subaddress_spend_public_key(index2); - m_subaddresses[D] = index2; - m_subaddresses_inv[index2] = D; - } + const crypto::public_key &D = pkeys[index2.minor]; + m_subaddresses[D] = index2; } } m_subaddress_labels.resize(index.major + 1, {"Untitled account"}); @@ -905,15 +902,14 @@ void wallet2::expand_subaddresses(const cryptonote::subaddress_index& index) else if (m_subaddress_labels[index.major].size() <= index.minor) { // add new subaddresses - cryptonote::subaddress_index index2 = index; - for (index2.minor = m_subaddress_labels[index.major].size(); index2.minor < index.minor + m_subaddress_lookahead_minor; ++index2.minor) + const uint32_t end = index.minor + m_subaddress_lookahead_minor; + const uint32_t begin = m_subaddress_labels[index.major].size(); + cryptonote::subaddress_index index2 = {index.major, begin}; + const std::vector<crypto::public_key> pkeys = cryptonote::get_subaddress_spend_public_keys(m_account.get_keys(), index2.major, index2.minor, end); + for (; index2.minor < end; ++index2.minor) { - if (m_subaddresses_inv.count(index2) == 0) - { - crypto::public_key D = get_subaddress_spend_public_key(index2); - m_subaddresses[D] = index2; - m_subaddresses_inv[index2] = D; - } + const crypto::public_key &D = pkeys[index2.minor - begin]; + m_subaddresses[D] = index2; } m_subaddress_labels[index.major].resize(index.minor + 1); } @@ -1219,7 +1215,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_rct = false; } set_unspent(m_transfers.size()-1); - if (!m_multisig) + if (!m_multisig && !m_watch_only) m_key_images[td.m_key_image] = m_transfers.size()-1; m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1; if (m_multisig) @@ -1313,11 +1309,21 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote uint64_t amount = boost::get<cryptonote::txin_to_key>(in).amount; if (amount > 0) { - THROW_WALLET_EXCEPTION_IF(amount != td.amount(), error::wallet_internal_error, - std::string("Inconsistent amount in tx input: got ") + print_money(amount) + - std::string(", expected ") + print_money(td.amount())); + if(amount != td.amount()) + { + MERROR("Inconsistent amount in tx input: got " << print_money(amount) << + ", expected " << print_money(td.amount())); + // this means: + // 1) the same output pub key was used as destination multiple times, + // 2) the wallet set the highest amount among them to transfer_details::m_amount, and + // 3) the wallet somehow spent that output with an amount smaller than the above amount, causing inconsistency + td.m_amount = amount; + } + } + else + { + amount = td.amount(); } - amount = td.amount(); tx_money_spent_in_ins += amount; if (subaddr_account && *subaddr_account != td.m_subaddr_index.major) LOG_ERROR("spent funds are from different subaddress accounts; count of incoming/outgoing payments will be incorrect"); @@ -2343,7 +2349,6 @@ bool wallet2::clear() m_address_book.clear(); m_local_bc_height = 1; m_subaddresses.clear(); - m_subaddresses_inv.clear(); m_subaddress_labels.clear(); return true; } @@ -2635,8 +2640,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_confirm_backlog_threshold = field_confirm_backlog_threshold; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_export_overwrite, int, Int, false, true); m_confirm_export_overwrite = field_confirm_export_overwrite; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, m_auto_low_priority, int, Int, false, true); - m_auto_low_priority = field_m_auto_low_priority; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, auto_low_priority, int, Int, false, true); + m_auto_low_priority = field_auto_low_priority; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, testnet, int, Int, false, m_testnet); // Wallet is being opened with testnet flag, but is saved as a mainnet wallet THROW_WALLET_EXCEPTION_IF(m_testnet && !field_testnet, error::wallet_internal_error, "Mainnet wallet can not be opened as testnet wallet"); @@ -3185,7 +3190,6 @@ bool wallet2::finalize_multisig(const epee::wipeable_string &password, std::unor } m_subaddresses.clear(); - m_subaddresses_inv.clear(); m_subaddress_labels.clear(); add_subaddress_account(tr("Primary account")); @@ -6642,7 +6646,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp uint64_t needed_fee, available_for_fee = 0; uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); const bool use_rct = use_fork_rules(4, 0); - const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0); + const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const uint64_t fee_per_kb = get_per_kb_fee(); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); @@ -7151,7 +7155,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton std::vector<std::vector<get_outs_entry>> outs; const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0); - const bool bulletproof = use_fork_rules(get_bulletproof_fork(m_testnet), 0); + const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const uint64_t fee_per_kb = get_per_kb_fee(); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); @@ -8354,8 +8358,9 @@ uint64_t wallet2::get_approximate_blockchain_height() const // Calculated blockchain height uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block; // testnet got some huge rollbacks, so the estimation is way off - if (m_testnet && approx_blockchain_height > 105000) - approx_blockchain_height -= 105000; + static const uint64_t approximate_testnet_rolled_back_blocks = 148540; + if (m_testnet && approx_blockchain_height > approximate_testnet_rolled_back_blocks) + approx_blockchain_height -= approximate_testnet_rolled_back_blocks; LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height); return approx_blockchain_height; } diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index f768581b2..28289842b 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -561,6 +561,9 @@ namespace tools void set_refresh_from_block_height(uint64_t height) {m_refresh_from_block_height = height;} uint64_t get_refresh_from_block_height() const {return m_refresh_from_block_height;} + void explicit_refresh_from_block_height(bool expl) {m_explicit_refresh_from_block_height = expl;} + bool explicit_refresh_from_block_height() const {return m_explicit_refresh_from_block_height;} + // upper_transaction_size_limit as defined below is set to // approximately 125% of the fixed minimum allowable penalty // free block size. TODO: fix this so that it actually takes @@ -602,6 +605,7 @@ namespace tools cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index& index) const; cryptonote::account_public_address get_address() const { return get_subaddress({0,0}); } crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const; + std::vector<crypto::public_key> get_subaddress_spend_public_keys(uint32_t account, uint32_t begin, uint32_t end) const; std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const; std::string get_address_as_str() const { return get_subaddress_as_str({0, 0}); } std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const; @@ -779,7 +783,8 @@ namespace tools if (ver < 20) return; a & m_subaddresses; - a & m_subaddresses_inv; + std::unordered_map<cryptonote::subaddress_index, crypto::public_key> dummy_subaddresses_inv; + a & dummy_subaddresses_inv; a & m_subaddress_labels; a & m_additional_tx_keys; if(ver < 21) @@ -1086,7 +1091,6 @@ namespace tools std::unordered_map<crypto::public_key, size_t> m_pub_keys; cryptonote::account_public_address m_account_public_address; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> m_subaddresses; - std::unordered_map<cryptonote::subaddress_index, crypto::public_key> m_subaddresses_inv; std::vector<std::vector<std::string>> m_subaddress_labels; std::unordered_map<crypto::hash, std::string> m_tx_notes; std::unordered_map<std::string, std::string> m_attributes; @@ -1117,6 +1121,9 @@ namespace tools RefreshType m_refresh_type; bool m_auto_refresh; uint64_t m_refresh_from_block_height; + // If m_refresh_from_block_height is explicitly set to zero we need this to differentiate it from the case that + // m_refresh_from_block_height was defaulted to zero.*/ + bool m_explicit_refresh_from_block_height; bool m_confirm_missing_payment_id; bool m_ask_password; uint32_t m_min_output_count; diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 97faf0b56..6d5419521 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -39,6 +39,7 @@ using namespace epee; #include "wallet/wallet_args.h" #include "common/command_line.h" #include "common/i18n.h" +#include "cryptonote_config.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/account.h" #include "multisig/multisig.h" @@ -1803,11 +1804,11 @@ namespace tools return false; } - uint64_t min_height = 0, max_height = (uint64_t)-1; + uint64_t min_height = 0, max_height = CRYPTONOTE_MAX_BLOCK_NUMBER; if (req.filter_by_height) { min_height = req.min_height; - max_height = req.max_height; + max_height = req.max_height <= max_height ? req.max_height : max_height; } if (req.in) @@ -1889,8 +1890,15 @@ namespace tools return false; } + if (req.account_index >= m_wallet->get_num_subaddress_accounts()) + { + er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS; + er.message = "Account index is out of bound"; + return false; + } + std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments; - m_wallet->get_payments(payments, 0); + m_wallet->get_payments(payments, 0, (uint64_t)-1, req.account_index); for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) { if (i->second.m_tx_hash == txid) { @@ -1900,7 +1908,7 @@ namespace tools } std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> payments_out; - m_wallet->get_payments_out(payments_out, 0); + m_wallet->get_payments_out(payments_out, 0, (uint64_t)-1, req.account_index); for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) { if (i->first == txid) { @@ -1910,7 +1918,7 @@ namespace tools } std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>> upayments; - m_wallet->get_unconfirmed_payments_out(upayments); + m_wallet->get_unconfirmed_payments_out(upayments, req.account_index); for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) { if (i->first == txid) { @@ -1922,7 +1930,7 @@ namespace tools m_wallet->update_pool_state(); std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> pool_payments; - m_wallet->get_unconfirmed_payments(pool_payments); + m_wallet->get_unconfirmed_payments(pool_payments, req.account_index); for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) { if (i->second.m_pd.m_tx_hash == txid) { @@ -2397,6 +2405,11 @@ namespace tools { std::rethrow_exception(e); } + catch (const tools::error::no_connection_to_daemon& e) + { + er.code = WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION; + er.message = e.what(); + } catch (const tools::error::daemon_busy& e) { er.code = WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY; @@ -2412,6 +2425,11 @@ namespace tools er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; er.message = e.what(); } + catch (const tools::error::not_enough_unlocked_money& e) + { + er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY; + er.message = e.what(); + } catch (const tools::error::tx_not_possible& e) { er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; @@ -2425,7 +2443,7 @@ namespace tools catch (const tools::error::not_enough_outs_to_mix& e) { er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX; - er.message = e.what(); + er.message = e.what() + std::string(" Please use sweep_dust."); } catch (const error::file_exists& e) { @@ -2439,12 +2457,12 @@ namespace tools } catch (const error::account_index_outofbound& e) { - er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUTOFBOUND; + er.code = WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS; er.message = e.what(); } catch (const error::address_index_outofbound& e) { - er.code = WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUTOFBOUND; + er.code = WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS; er.message = e.what(); } catch (const std::exception& e) @@ -2922,12 +2940,12 @@ int main(int argc, char** argv) { // if we ^C during potentially length load/refresh, there's no server loop yet if (quit) { - MINFO(tools::wallet_rpc_server::tr("Storing wallet...")); + MINFO(tools::wallet_rpc_server::tr("Saving wallet...")); wal->store(); - MINFO(tools::wallet_rpc_server::tr("Stored ok")); + MINFO(tools::wallet_rpc_server::tr("Successfully saved")); return 1; } - MINFO(tools::wallet_rpc_server::tr("Loaded ok")); + MINFO(tools::wallet_rpc_server::tr("Successfully loaded")); } catch (const std::exception& e) { @@ -2938,11 +2956,11 @@ just_dir: tools::wallet_rpc_server wrpc; if (wal) wrpc.set_wallet(wal.release()); bool r = wrpc.init(&(vm.get())); - CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet rpc server")); + CHECK_AND_ASSERT_MES(r, 1, tools::wallet_rpc_server::tr("Failed to initialize wallet RPC server")); tools::signal_handler::install([&wrpc](int) { wrpc.send_stop_signal(); }); - LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet rpc server")); + LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet RPC server")); try { wrpc.run(); @@ -2952,16 +2970,16 @@ just_dir: LOG_ERROR(tools::wallet_rpc_server::tr("Failed to run wallet: ") << e.what()); return 1; } - LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet rpc server")); + LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stopped wallet RPC server")); try { - LOG_PRINT_L0(tools::wallet_rpc_server::tr("Storing wallet...")); + LOG_PRINT_L0(tools::wallet_rpc_server::tr("Saving wallet...")); wrpc.stop(); - LOG_PRINT_L0(tools::wallet_rpc_server::tr("Stored ok")); + LOG_PRINT_L0(tools::wallet_rpc_server::tr("Successfully saved")); } catch (const std::exception& e) { - LOG_ERROR(tools::wallet_rpc_server::tr("Failed to store wallet: ") << e.what()); + LOG_ERROR(tools::wallet_rpc_server::tr("Failed to save wallet: ") << e.what()); return 1; } return 0; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index e9f112b63..e38cba5a5 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -29,6 +29,7 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once +#include "cryptonote_config.h" #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "cryptonote_basic/cryptonote_basic.h" #include "cryptonote_basic/subaddress_index.h" @@ -1262,7 +1263,7 @@ namespace wallet_rpc KV_SERIALIZE(pool); KV_SERIALIZE(filter_by_height); KV_SERIALIZE(min_height); - KV_SERIALIZE(max_height); + KV_SERIALIZE_OPT(max_height, (uint64_t)CRYPTONOTE_MAX_BLOCK_NUMBER); KV_SERIALIZE(account_index); KV_SERIALIZE(subaddr_indices); END_KV_SERIALIZE_MAP() @@ -1291,9 +1292,11 @@ namespace wallet_rpc struct request { std::string txid; + uint32_t account_index; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(txid); + KV_SERIALIZE_OPT(account_index, (uint32_t)0) 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 311556657..d47467940 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -44,8 +44,8 @@ #define WALLET_RPC_ERROR_CODE_WRONG_URI -11 #define WALLET_RPC_ERROR_CODE_WRONG_INDEX -12 #define WALLET_RPC_ERROR_CODE_NOT_OPEN -13 -#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUTOFBOUND -14 -#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUTOFBOUND -15 +#define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS -14 +#define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS -15 #define WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE -16 #define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -17 #define WALLET_RPC_ERROR_CODE_TX_TOO_LARGE -18 @@ -67,3 +67,5 @@ #define WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA -34 #define WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE -35 #define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION -36 +#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY -37 +#define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION -38 |