summaryrefslogtreecommitdiff
path: root/patches/0003-coin-control.patch
diff options
context:
space:
mode:
authorCzarek Nakamoto <cyjan@mrcyjanek.net>2024-03-22 14:21:57 +0100
committerCzarek Nakamoto <cyjan@mrcyjanek.net>2024-03-22 14:21:57 +0100
commit380f3f41e62cb72ed24e4f46df78f36f8e28c6d6 (patch)
treee536ad49963dcf85d176bed157059f7d8397c224 /patches/0003-coin-control.patch
parent8775db7e945552e4f23c429dde4ddf91d974a5a2 (diff)
wow + build
Diffstat (limited to 'patches/0003-coin-control.patch')
-rw-r--r--patches/0003-coin-control.patch916
1 files changed, 0 insertions, 916 deletions
diff --git a/patches/0003-coin-control.patch b/patches/0003-coin-control.patch
deleted file mode 100644
index 2d25beb..0000000
--- a/patches/0003-coin-control.patch
+++ /dev/null
@@ -1,916 +0,0 @@
-From a95f52274d4a6a467e06bff60121850adba387ad Mon Sep 17 00:00:00 2001
-From: Czarek Nakamoto <cyjan@mrcyjanek.net>
-Date: Tue, 12 Mar 2024 11:07:57 +0100
-Subject: [PATCH] PATCH: coin control
-
----
- src/wallet/api/CMakeLists.txt | 8 +-
- src/wallet/api/coins.cpp | 185 ++++++++++++++++++++++++++++++++++
- src/wallet/api/coins.h | 40 ++++++++
- src/wallet/api/coins_info.cpp | 122 ++++++++++++++++++++++
- src/wallet/api/coins_info.h | 71 +++++++++++++
- src/wallet/api/wallet.cpp | 31 +++++-
- src/wallet/api/wallet.h | 10 +-
- src/wallet/api/wallet2_api.h | 52 +++++++++-
- src/wallet/wallet2.cpp | 46 ++++++++-
- src/wallet/wallet2.h | 11 +-
- 10 files changed, 558 insertions(+), 18 deletions(-)
- create mode 100644 src/wallet/api/coins.cpp
- create mode 100644 src/wallet/api/coins.h
- create mode 100644 src/wallet/api/coins_info.cpp
- create mode 100644 src/wallet/api/coins_info.h
-
-diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt
-index af7948d8a..bb740e2ac 100644
---- a/src/wallet/api/CMakeLists.txt
-+++ b/src/wallet/api/CMakeLists.txt
-@@ -40,7 +40,9 @@ set(wallet_api_sources
- address_book.cpp
- subaddress.cpp
- subaddress_account.cpp
-- unsigned_transaction.cpp)
-+ unsigned_transaction.cpp
-+ coins.cpp
-+ coins_info.cpp)
-
- set(wallet_api_headers
- wallet2_api.h)
-@@ -55,7 +57,9 @@ set(wallet_api_private_headers
- address_book.h
- subaddress.h
- subaddress_account.h
-- unsigned_transaction.h)
-+ unsigned_transaction.h
-+ coins.h
-+ coins_info.h)
-
- monero_private_headers(wallet_api
- ${wallet_api_private_headers})
-diff --git a/src/wallet/api/coins.cpp b/src/wallet/api/coins.cpp
-new file mode 100644
-index 000000000..2321c638d
---- /dev/null
-+++ b/src/wallet/api/coins.cpp
-@@ -0,0 +1,185 @@
-+#include "coins.h"
-+#include "coins_info.h"
-+#include "wallet.h"
-+#include "crypto/hash.h"
-+#include "wallet/wallet2.h"
-+#include "common_defines.h"
-+
-+#include <string>
-+#include <vector>
-+
-+using namespace epee;
-+
-+namespace Monero {
-+
-+Coins::~Coins() = default;
-+
-+CoinsImpl::CoinsImpl(WalletImpl *wallet)
-+ : m_wallet(wallet) {}
-+
-+CoinsImpl::~CoinsImpl()
-+{
-+ for (auto t : m_rows)
-+ delete t;
-+}
-+
-+int CoinsImpl::count() const
-+{
-+ boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
-+ int result = m_rows.size();
-+ return result;
-+}
-+
-+CoinsInfo *CoinsImpl::coin(int index) const
-+{
-+ boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
-+ // sanity check
-+ if (index < 0)
-+ return nullptr;
-+ auto index_ = static_cast<unsigned>(index);
-+ return index_ < m_rows.size() ? m_rows[index_] : nullptr;
-+}
-+
-+std::vector<CoinsInfo *> CoinsImpl::getAll() const
-+{
-+ boost::shared_lock<boost::shared_mutex> lock(m_rowsMutex);
-+ return m_rows;
-+}
-+
-+
-+void CoinsImpl::refresh()
-+{
-+ LOG_PRINT_L2("Refreshing coins");
-+
-+ boost::unique_lock<boost::shared_mutex> lock(m_rowsMutex);
-+ boost::shared_lock<boost::shared_mutex> transfers_lock(m_wallet->m_wallet->m_transfers_mutex);
-+
-+ // delete old outputs;
-+ for (auto t : m_rows)
-+ delete t;
-+ m_rows.clear();
-+
-+ for (size_t i = 0; i < m_wallet->m_wallet->get_num_transfer_details(); ++i)
-+ {
-+ const tools::wallet2::transfer_details &td = m_wallet->m_wallet->get_transfer_details(i);
-+
-+ auto ci = new CoinsInfoImpl();
-+ ci->m_blockHeight = td.m_block_height;
-+ ci->m_hash = string_tools::pod_to_hex(td.m_txid);
-+ ci->m_internalOutputIndex = td.m_internal_output_index;
-+ ci->m_globalOutputIndex = td.m_global_output_index;
-+ ci->m_spent = td.m_spent;
-+ ci->m_frozen = td.m_frozen;
-+ ci->m_spentHeight = td.m_spent_height;
-+ ci->m_amount = td.m_amount;
-+ ci->m_rct = td.m_rct;
-+ ci->m_keyImageKnown = td.m_key_image_known;
-+ ci->m_pkIndex = td.m_pk_index;
-+ ci->m_subaddrIndex = td.m_subaddr_index.minor;
-+ ci->m_subaddrAccount = td.m_subaddr_index.major;
-+ ci->m_address = m_wallet->m_wallet->get_subaddress_as_str(td.m_subaddr_index); // todo: this is expensive, cache maybe?
-+ ci->m_addressLabel = m_wallet->m_wallet->get_subaddress_label(td.m_subaddr_index);
-+ ci->m_keyImage = string_tools::pod_to_hex(td.m_key_image);
-+ ci->m_unlockTime = td.m_tx.unlock_time;
-+ ci->m_unlocked = m_wallet->m_wallet->is_transfer_unlocked(td);
-+ ci->m_pubKey = string_tools::pod_to_hex(td.get_public_key());
-+ ci->m_coinbase = td.m_tx.vin.size() == 1 && td.m_tx.vin[0].type() == typeid(cryptonote::txin_gen);
-+ ci->m_description = m_wallet->m_wallet->get_tx_note(td.m_txid);
-+
-+ m_rows.push_back(ci);
-+ }
-+}
-+
-+void CoinsImpl::setFrozen(std::string public_key)
-+{
-+ crypto::public_key pk;
-+ if (!epee::string_tools::hex_to_pod(public_key, pk))
-+ {
-+ LOG_ERROR("Invalid public key: " << public_key);
-+ return;
-+ }
-+
-+ try
-+ {
-+ m_wallet->m_wallet->freeze(pk);
-+ refresh();
-+ }
-+ catch (const std::exception& e)
-+ {
-+ LOG_ERROR("setFrozen: " << e.what());
-+ }
-+}
-+
-+void CoinsImpl::setFrozen(int index)
-+{
-+ try
-+ {
-+ m_wallet->m_wallet->freeze(index);
-+ refresh();
-+ }
-+ catch (const std::exception& e)
-+ {
-+ LOG_ERROR("setLabel: " << e.what());
-+ }
-+}
-+
-+void CoinsImpl::thaw(std::string public_key)
-+{
-+ crypto::public_key pk;
-+ if (!epee::string_tools::hex_to_pod(public_key, pk))
-+ {
-+ LOG_ERROR("Invalid public key: " << public_key);
-+ return;
-+ }
-+
-+ try
-+ {
-+ m_wallet->m_wallet->thaw(pk);
-+ refresh();
-+ }
-+ catch (const std::exception& e)
-+ {
-+ LOG_ERROR("thaw: " << e.what());
-+ }
-+}
-+
-+void CoinsImpl::thaw(int index)
-+{
-+ try
-+ {
-+ m_wallet->m_wallet->thaw(index);
-+ refresh();
-+ }
-+ catch (const std::exception& e)
-+ {
-+ LOG_ERROR("thaw: " << e.what());
-+ }
-+}
-+
-+bool CoinsImpl::isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) {
-+ return m_wallet->m_wallet->is_transfer_unlocked(unlockTime, blockHeight);
-+}
-+
-+void CoinsImpl::setDescription(const std::string &public_key, const std::string &description)
-+{
-+ crypto::public_key pk;
-+ if (!epee::string_tools::hex_to_pod(public_key, pk))
-+ {
-+ LOG_ERROR("Invalid public key: " << public_key);
-+ return;
-+ }
-+
-+ try
-+ {
-+ const size_t index = m_wallet->m_wallet->get_transfer_details(pk);
-+ const tools::wallet2::transfer_details &td = m_wallet->m_wallet->get_transfer_details(index);
-+ m_wallet->m_wallet->set_tx_note(td.m_txid, description);
-+ refresh();
-+ }
-+ catch (const std::exception& e)
-+ {
-+ LOG_ERROR("setDescription: " << e.what());
-+ }
-+}
-+
-+} // namespace
-diff --git a/src/wallet/api/coins.h b/src/wallet/api/coins.h
-new file mode 100644
-index 000000000..b7a0a8642
---- /dev/null
-+++ b/src/wallet/api/coins.h
-@@ -0,0 +1,40 @@
-+#ifndef FEATHER_COINS_H
-+#define FEATHER_COINS_H
-+
-+#include "wallet/api/wallet2_api.h"
-+#include "wallet/wallet2.h"
-+
-+namespace Monero {
-+
-+class WalletImpl;
-+
-+class CoinsImpl : public Coins
-+{
-+public:
-+ explicit CoinsImpl(WalletImpl * wallet);
-+ ~CoinsImpl() override;
-+ int count() const override;
-+ CoinsInfo * coin(int index) const override;
-+ std::vector<CoinsInfo*> getAll() const override;
-+ void refresh() override;
-+
-+ void setFrozen(std::string public_key) override;
-+ void setFrozen(int index) override;
-+ void thaw(std::string public_key) override;
-+ void thaw(int index) override;
-+
-+ bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) override;
-+
-+ void setDescription(const std::string &public_key, const std::string &description) override;
-+
-+private:
-+ WalletImpl *m_wallet;
-+ std::vector<CoinsInfo*> m_rows;
-+ mutable boost::shared_mutex m_rowsMutex;
-+};
-+
-+}
-+
-+namespace Bitmonero = Monero;
-+
-+#endif //FEATHER_COINS_H
-diff --git a/src/wallet/api/coins_info.cpp b/src/wallet/api/coins_info.cpp
-new file mode 100644
-index 000000000..5f2c4e1e4
---- /dev/null
-+++ b/src/wallet/api/coins_info.cpp
-@@ -0,0 +1,122 @@
-+#include "coins_info.h"
-+
-+using namespace std;
-+
-+namespace Monero {
-+
-+CoinsInfo::~CoinsInfo() = default;
-+
-+CoinsInfoImpl::CoinsInfoImpl()
-+ : m_blockHeight(0)
-+ , m_internalOutputIndex(0)
-+ , m_globalOutputIndex(0)
-+ , m_spent(false)
-+ , m_frozen(false)
-+ , m_spentHeight(0)
-+ , m_amount(0)
-+ , m_rct(false)
-+ , m_keyImageKnown(false)
-+ , m_pkIndex(0)
-+ , m_subaddrAccount(0)
-+ , m_subaddrIndex(0)
-+ , m_unlockTime(0)
-+ , m_unlocked(false)
-+{
-+
-+}
-+
-+CoinsInfoImpl::~CoinsInfoImpl() = default;
-+
-+uint64_t CoinsInfoImpl::blockHeight() const
-+{
-+ return m_blockHeight;
-+}
-+
-+string CoinsInfoImpl::hash() const
-+{
-+ return m_hash;
-+}
-+
-+size_t CoinsInfoImpl::internalOutputIndex() const {
-+ return m_internalOutputIndex;
-+}
-+
-+uint64_t CoinsInfoImpl::globalOutputIndex() const
-+{
-+ return m_globalOutputIndex;
-+}
-+
-+bool CoinsInfoImpl::spent() const
-+{
-+ return m_spent;
-+}
-+
-+bool CoinsInfoImpl::frozen() const
-+{
-+ return m_frozen;
-+}
-+
-+uint64_t CoinsInfoImpl::spentHeight() const
-+{
-+ return m_spentHeight;
-+}
-+
-+uint64_t CoinsInfoImpl::amount() const
-+{
-+ return m_amount;
-+}
-+
-+bool CoinsInfoImpl::rct() const {
-+ return m_rct;
-+}
-+
-+bool CoinsInfoImpl::keyImageKnown() const {
-+ return m_keyImageKnown;
-+}
-+
-+size_t CoinsInfoImpl::pkIndex() const {
-+ return m_pkIndex;
-+}
-+
-+uint32_t CoinsInfoImpl::subaddrIndex() const {
-+ return m_subaddrIndex;
-+}
-+
-+uint32_t CoinsInfoImpl::subaddrAccount() const {
-+ return m_subaddrAccount;
-+}
-+
-+string CoinsInfoImpl::address() const {
-+ return m_address;
-+}
-+
-+string CoinsInfoImpl::addressLabel() const {
-+ return m_addressLabel;
-+}
-+
-+string CoinsInfoImpl::keyImage() const {
-+ return m_keyImage;
-+}
-+
-+uint64_t CoinsInfoImpl::unlockTime() const {
-+ return m_unlockTime;
-+}
-+
-+bool CoinsInfoImpl::unlocked() const {
-+ return m_unlocked;
-+}
-+
-+string CoinsInfoImpl::pubKey() const {
-+ return m_pubKey;
-+}
-+
-+bool CoinsInfoImpl::coinbase() const {
-+ return m_coinbase;
-+}
-+
-+string CoinsInfoImpl::description() const {
-+ return m_description;
-+}
-+} // namespace
-+
-+namespace Bitmonero = Monero;
-diff --git a/src/wallet/api/coins_info.h b/src/wallet/api/coins_info.h
-new file mode 100644
-index 000000000..c43e45abd
---- /dev/null
-+++ b/src/wallet/api/coins_info.h
-@@ -0,0 +1,71 @@
-+#ifndef FEATHER_COINS_INFO_H
-+#define FEATHER_COINS_INFO_H
-+
-+#include "wallet/api/wallet2_api.h"
-+#include <string>
-+#include <ctime>
-+
-+namespace Monero {
-+
-+class CoinsImpl;
-+
-+class CoinsInfoImpl : public CoinsInfo
-+{
-+public:
-+ CoinsInfoImpl();
-+ ~CoinsInfoImpl();
-+
-+ virtual uint64_t blockHeight() const override;
-+ virtual std::string hash() const override;
-+ virtual size_t internalOutputIndex() const override;
-+ virtual uint64_t globalOutputIndex() const override;
-+ virtual bool spent() const override;
-+ virtual bool frozen() const override;
-+ virtual uint64_t spentHeight() const override;
-+ virtual uint64_t amount() const override;
-+ virtual bool rct() const override;
-+ virtual bool keyImageKnown() const override;
-+ virtual size_t pkIndex() const override;
-+ virtual uint32_t subaddrIndex() const override;
-+ virtual uint32_t subaddrAccount() const override;
-+ virtual std::string address() const override;
-+ virtual std::string addressLabel() const override;
-+ virtual std::string keyImage() const override;
-+ virtual uint64_t unlockTime() const override;
-+ virtual bool unlocked() const override;
-+ virtual std::string pubKey() const override;
-+ virtual bool coinbase() const override;
-+ virtual std::string description() const override;
-+
-+private:
-+ uint64_t m_blockHeight;
-+ std::string m_hash;
-+ size_t m_internalOutputIndex;
-+ uint64_t m_globalOutputIndex;
-+ bool m_spent;
-+ bool m_frozen;
-+ uint64_t m_spentHeight;
-+ uint64_t m_amount;
-+ bool m_rct;
-+ bool m_keyImageKnown;
-+ size_t m_pkIndex;
-+ uint32_t m_subaddrIndex;
-+ uint32_t m_subaddrAccount;
-+ std::string m_address;
-+ std::string m_addressLabel;
-+ std::string m_keyImage;
-+ uint64_t m_unlockTime;
-+ bool m_unlocked;
-+ std::string m_pubKey;
-+ bool m_coinbase;
-+ std::string m_description;
-+
-+ friend class CoinsImpl;
-+
-+};
-+
-+} // namespace
-+
-+namespace Bitmonero = Monero;
-+
-+#endif //FEATHER_COINS_INFO_H
-diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
-index 42887dced..2fe0d1d29 100644
---- a/src/wallet/api/wallet.cpp
-+++ b/src/wallet/api/wallet.cpp
-@@ -35,6 +35,7 @@
- #include "transaction_history.h"
- #include "address_book.h"
- #include "subaddress.h"
-+#include "coins.h"
- #include "subaddress_account.h"
- #include "common_defines.h"
- #include "common/util.h"
-@@ -469,6 +470,7 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
- m_refreshEnabled = false;
- m_addressBook.reset(new AddressBookImpl(this));
- m_subaddress.reset(new SubaddressImpl(this));
-+ m_coins.reset(new CoinsImpl(this));
- m_subaddressAccount.reset(new SubaddressAccountImpl(this));
-
-
-@@ -1752,7 +1754,7 @@ PendingTransaction* WalletImpl::restoreMultisigTransaction(const string& signDat
- // - unconfirmed_transfer_details;
- // - confirmed_transfer_details)
-
--PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
-+PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<string> &dst_addr, const string &payment_id, optional<std::vector<uint64_t>> amount, uint32_t mixin_count, PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
-
- {
- clearStatus();
-@@ -1821,6 +1823,19 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
- }
- }
- }
-+ std::vector<crypto::key_image> preferred_input_list;
-+ if (!preferred_inputs.empty()) {
-+ for (const auto &public_key : preferred_inputs) {
-+ crypto::key_image keyImage;
-+ bool r = epee::string_tools::hex_to_pod(public_key, keyImage);
-+ if (!r) {
-+ error = true;
-+ setStatusError(tr("failed to parse key image"));
-+ break;
-+ }
-+ preferred_input_list.push_back(keyImage);
-+ }
-+ }
- if (error) {
- break;
- }
-@@ -1833,13 +1848,14 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
- fake_outs_count = m_wallet->adjust_mixin(mixin_count);
-
- if (amount) {
-+ // (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, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs, const std::vector<crypto::key_image>& preferred_input_list)
- transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */,
- adjusted_priority,
-- extra, subaddr_account, subaddr_indices);
-+ extra, subaddr_account, subaddr_indices, preferred_input_list);
- } else {
- transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */,
- adjusted_priority,
-- extra, subaddr_account, subaddr_indices);
-+ extra, subaddr_account, subaddr_indices, preferred_input_list);
- }
- pendingTxPostProcess(transaction);
-
-@@ -1920,10 +1936,10 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri
- }
-
- PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const string &payment_id, optional<uint64_t> amount, uint32_t mixin_count,
-- PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
-+ PendingTransaction::Priority priority, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::set<std::string> &preferred_inputs)
-
- {
-- return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices);
-+ return createTransactionMultDest(std::vector<string> {dst_addr}, payment_id, amount ? (std::vector<uint64_t> {*amount}) : (optional<std::vector<uint64_t>>()), mixin_count, priority, subaddr_account, subaddr_indices, preferred_inputs);
- }
-
- PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
-@@ -2048,6 +2064,11 @@ AddressBook *WalletImpl::addressBook()
- return m_addressBook.get();
- }
-
-+Coins *WalletImpl::coins()
-+{
-+ return m_coins.get();
-+}
-+
- Subaddress *WalletImpl::subaddress()
- {
- return m_subaddress.get();
-diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h
-index 05d065c5c..4a16ca028 100644
---- a/src/wallet/api/wallet.h
-+++ b/src/wallet/api/wallet.h
-@@ -46,6 +46,7 @@ class PendingTransactionImpl;
- class UnsignedTransactionImpl;
- class AddressBookImpl;
- class SubaddressImpl;
-+class CoinsImpl;
- class SubaddressAccountImpl;
- struct Wallet2CallbackImpl;
-
-@@ -167,12 +168,14 @@ public:
- optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
- PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
- uint32_t subaddr_account = 0,
-- std::set<uint32_t> subaddr_indices = {}) override;
-+ std::set<uint32_t> subaddr_indices = {},
-+ const std::set<std::string> &preferred_inputs = {}) override;
- PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id,
- optional<uint64_t> amount, uint32_t mixin_count,
- PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
- uint32_t subaddr_account = 0,
-- std::set<uint32_t> subaddr_indices = {}) override;
-+ std::set<uint32_t> subaddr_indices = {},
-+ const std::set<std::string> &preferred_inputs = {}) override;
- virtual PendingTransaction * createSweepUnmixableTransaction() override;
- bool submitTransaction(const std::string &fileName) override;
- virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
-@@ -195,6 +198,7 @@ public:
- PendingTransaction::Priority priority) const override;
- virtual TransactionHistory * history() override;
- virtual AddressBook * addressBook() override;
-+ virtual Coins * coins() override;
- virtual Subaddress * subaddress() override;
- virtual SubaddressAccount * subaddressAccount() override;
- virtual void setListener(WalletListener * l) override;
-@@ -266,6 +270,7 @@ private:
- friend class TransactionHistoryImpl;
- friend struct Wallet2CallbackImpl;
- friend class AddressBookImpl;
-+ friend class CoinsImpl;
- friend class SubaddressImpl;
- friend class SubaddressAccountImpl;
-
-@@ -282,6 +287,7 @@ private:
- std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
- std::unique_ptr<AddressBookImpl> m_addressBook;
- std::unique_ptr<SubaddressImpl> m_subaddress;
-+ std::unique_ptr<CoinsImpl> m_coins;
- std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
-
- // multi-threaded refresh stuff
-diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h
-index 4edaefefd..8a5c4135e 100644
---- a/src/wallet/api/wallet2_api.h
-+++ b/src/wallet/api/wallet2_api.h
-@@ -261,6 +261,51 @@ struct AddressBook
- virtual int lookupPaymentID(const std::string &payment_id) const = 0;
- };
-
-+/**
-+ * @brief The CoinsInfo - interface for displaying coins information
-+ */
-+struct CoinsInfo
-+{
-+ virtual ~CoinsInfo() = 0;
-+
-+ virtual uint64_t blockHeight() const = 0;
-+ virtual std::string hash() const = 0;
-+ virtual size_t internalOutputIndex() const = 0;
-+ virtual uint64_t globalOutputIndex() const = 0;
-+ virtual bool spent() const = 0;
-+ virtual bool frozen() const = 0;
-+ virtual uint64_t spentHeight() const = 0;
-+ virtual uint64_t amount() const = 0;
-+ virtual bool rct() const = 0;
-+ virtual bool keyImageKnown() const = 0;
-+ virtual size_t pkIndex() const = 0;
-+ virtual uint32_t subaddrIndex() const = 0;
-+ virtual uint32_t subaddrAccount() const = 0;
-+ virtual std::string address() const = 0;
-+ virtual std::string addressLabel() const = 0;
-+ virtual std::string keyImage() const = 0;
-+ virtual uint64_t unlockTime() const = 0;
-+ virtual bool unlocked() const = 0;
-+ virtual std::string pubKey() const = 0;
-+ virtual bool coinbase() const = 0;
-+ virtual std::string description() const = 0;
-+};
-+
-+struct Coins
-+{
-+ virtual ~Coins() = 0;
-+ virtual int count() const = 0;
-+ virtual CoinsInfo * coin(int index) const = 0;
-+ virtual std::vector<CoinsInfo*> getAll() const = 0;
-+ virtual void refresh() = 0;
-+ virtual void setFrozen(std::string public_key) = 0;
-+ virtual void setFrozen(int index) = 0;
-+ virtual void thaw(std::string public_key) = 0;
-+ virtual void thaw(int index) = 0;
-+ virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0;
-+ virtual void setDescription(const std::string &public_key, const std::string &description) = 0;
-+};
-+
- struct SubaddressRow {
- public:
- SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label):
-@@ -854,7 +899,8 @@ struct Wallet
- optional<std::vector<uint64_t>> amount, uint32_t mixin_count,
- PendingTransaction::Priority = PendingTransaction::Priority_Low,
- uint32_t subaddr_account = 0,
-- std::set<uint32_t> subaddr_indices = {}) = 0;
-+ std::set<uint32_t> subaddr_indices = {},
-+ const std::set<std::string> &preferred_inputs = {}) = 0;
-
- /*!
- * \brief createTransaction creates transaction. if dst_addr is an integrated address, payment_id is ignored
-@@ -873,7 +919,8 @@ struct Wallet
- optional<uint64_t> amount, uint32_t mixin_count,
- PendingTransaction::Priority = PendingTransaction::Priority_Low,
- uint32_t subaddr_account = 0,
-- std::set<uint32_t> subaddr_indices = {}) = 0;
-+ std::set<uint32_t> subaddr_indices = {},
-+ const std::set<std::string> &preferred_inputs = {}) = 0;
-
- /*!
- * \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
-@@ -987,6 +1034,7 @@ struct Wallet
-
- virtual TransactionHistory * history() = 0;
- virtual AddressBook * addressBook() = 0;
-+ virtual Coins * coins() = 0;
- virtual Subaddress * subaddress() = 0;
- virtual SubaddressAccount * subaddressAccount() = 0;
- virtual void setListener(WalletListener *) = 0;
-diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
-index 3477e084f..c3376f7e0 100644
---- a/src/wallet/wallet2.cpp
-+++ b/src/wallet/wallet2.cpp
-@@ -2081,12 +2081,21 @@ bool wallet2::frozen(const multisig_tx_set& txs) const
-
- return false;
- }
-+void wallet2::freeze(const crypto::public_key &pk)
-+{
-+ freeze(get_transfer_details(pk));
-+}
- //----------------------------------------------------------------------------------------------------
- void wallet2::freeze(const crypto::key_image &ki)
- {
- freeze(get_transfer_details(ki));
- }
- //----------------------------------------------------------------------------------------------------
-+void wallet2::thaw(const crypto::public_key &pk)
-+{
-+ thaw(get_transfer_details(pk));
-+}
-+//----------------------------------------------------------------------------------------------------
- void wallet2::thaw(const crypto::key_image &ki)
- {
- thaw(get_transfer_details(ki));
-@@ -2097,6 +2106,18 @@ bool wallet2::frozen(const crypto::key_image &ki) const
- return frozen(get_transfer_details(ki));
- }
- //----------------------------------------------------------------------------------------------------
-+size_t wallet2::get_transfer_details(const crypto::public_key &pk) const
-+{
-+ for (size_t idx = 0; idx < m_transfers.size(); ++idx)
-+ {
-+ const transfer_details &td = m_transfers[idx];
-+ if (td.get_public_key() == pk) {
-+ return idx;
-+ }
-+ }
-+ CHECK_AND_ASSERT_THROW_MES(false, "Public key not found");
-+}
-+//----------------------------------------------------------------------------------------------------
- size_t wallet2::get_transfer_details(const crypto::key_image &ki) const
- {
- for (size_t idx = 0; idx < m_transfers.size(); ++idx)
-@@ -2500,6 +2521,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
- uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
- if (!pool)
- {
-+ boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
- m_transfers.push_back(transfer_details{});
- transfer_details& td = m_transfers.back();
- td.m_block_height = height;
-@@ -2603,6 +2625,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
- uint64_t extra_amount = amount - burnt;
- if (!pool)
- {
-+ boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
- transfer_details &td = m_transfers[kit->second];
- td.m_block_height = height;
- td.m_internal_output_index = o;
-@@ -10495,7 +10518,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
- LOG_PRINT_L2("transfer_selected_rct done");
- }
-
--std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices)
-+std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list)
- {
- std::vector<size_t> picks;
- float current_output_relatdness = 1.0f;
-@@ -10506,6 +10529,9 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
- for (size_t i = 0; i < m_transfers.size(); ++i)
- {
- const transfer_details& td = m_transfers[i];
-+ if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
-+ continue;
-+ }
- if (!is_spent(td, false) && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
- {
- if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
-@@ -10526,6 +10552,9 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
- for (size_t i = 0; i < m_transfers.size(); ++i)
- {
- const transfer_details& td = m_transfers[i];
-+ if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
-+ continue;
-+ }
- if (!is_spent(td, false) && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
- {
- if (td.amount() > m_ignore_outputs_above || td.amount() < m_ignore_outputs_below)
-@@ -10537,6 +10566,9 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
- for (size_t j = i + 1; j < m_transfers.size(); ++j)
- {
- const transfer_details& td2 = m_transfers[j];
-+ if (!is_preferred_input(preferred_input_list, td2.m_key_image)) {
-+ continue;
-+ }
- if (td2.amount() > m_ignore_outputs_above || td2.amount() < m_ignore_outputs_below)
- {
- MDEBUG("Ignoring output " << j << " of amount " << print_money(td2.amount()) << " which is outside prescribed range [" << print_money(m_ignore_outputs_below) << ", " << print_money(m_ignore_outputs_above) << "]");
-@@ -11109,7 +11141,7 @@ bool wallet2::light_wallet_key_image_is_ours(const crypto::key_image& key_image,
- // 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, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs)
-+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, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list, const unique_index_container& subtract_fee_from_outputs)
- {
- //ensure device is let in NONE mode in any case
- hw::device &hwdev = m_account.get_device();
-@@ -11317,6 +11349,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
- for (size_t i = 0; i < m_transfers.size(); ++i)
- {
- const transfer_details& td = m_transfers[i];
-+ if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
-+ continue;
-+ }
- if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
- {
- MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below fractional threshold " << print_money(fractional_threshold));
-@@ -11401,7 +11436,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
- // will get us a known fee.
- uint64_t estimated_fee = estimate_fee(use_per_byte_fee, use_rct, 2, fake_outs_count, 2, extra.size(), bulletproof, clsag, bulletproof_plus, use_view_tags, base_fee, fee_quantization_mask);
- total_needed_money = needed_money + (subtract_fee_from_outputs.size() ? 0 : estimated_fee);
-- preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices);
-+ preferred_inputs = pick_preferred_rct_inputs(total_needed_money, subaddr_account, subaddr_indices, preferred_input_list);
- if (!preferred_inputs.empty())
- {
- string s;
-@@ -11882,7 +11917,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c
- return true;
- }
-
--std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices)
-+std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list)
- {
- std::vector<size_t> unused_transfers_indices;
- std::vector<size_t> unused_dust_indices;
-@@ -11911,6 +11946,9 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
- for (size_t i = 0; i < m_transfers.size(); ++i)
- {
- const transfer_details& td = m_transfers[i];
-+ if (!is_preferred_input(preferred_input_list, td.m_key_image)) {
-+ continue;
-+ }
- if (m_ignore_fractional_outputs && td.amount() < fractional_threshold)
- {
- MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
-diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
-index 406acac2b..5eae908ad 100644
---- a/src/wallet/wallet2.h
-+++ b/src/wallet/wallet2.h
-@@ -1207,8 +1207,8 @@ private:
- bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const;
- bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL);
- bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func);
-- 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, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
-- std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices);
-+ 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, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list = {}, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose
-+ std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list = {});
- std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
- std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra);
- bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const;
-@@ -1559,6 +1559,7 @@ private:
- uint64_t get_num_rct_outputs();
- size_t get_num_transfer_details() const { return m_transfers.size(); }
- const transfer_details &get_transfer_details(size_t idx) const;
-+ size_t get_transfer_details(const crypto::public_key &pk) const;
-
- uint8_t get_current_hard_fork();
- void get_hard_fork_info(uint8_t version, uint64_t &earliest_height);
-@@ -1788,7 +1789,9 @@ private:
- void freeze(size_t idx);
- void thaw(size_t idx);
- bool frozen(size_t idx) const;
-+ void freeze(const crypto::public_key &pk);
- void freeze(const crypto::key_image &ki);
-+ void thaw(const crypto::public_key &pk);
- void thaw(const crypto::key_image &ki);
- bool frozen(const crypto::key_image &ki) const;
- bool frozen(const transfer_details &td) const;
-@@ -1829,6 +1832,8 @@ private:
-
- static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; }
-
-+ boost::shared_mutex m_transfers_mutex;
-+
- private:
- /*!
- * \brief Stores wallet information to wallet file.
-@@ -1892,7 +1897,7 @@ private:
- std::vector<uint64_t> get_unspent_amounts_vector(bool strict);
- uint64_t get_dynamic_base_fee_estimate();
- float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
-- std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices);
-+ std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set<uint32_t> &subaddr_indices, const std::vector<crypto::key_image>& preferred_input_list);
- void set_spent(size_t idx, uint64_t height);
- void set_unspent(size_t idx);
- bool is_spent(const transfer_details &td, bool strict = true) const;