Merge pull request #7678

dedcd63 wallet_api: import / export output function (tobtoht)
6e22710 expose set_offline to wallet api (benevanoff)
02e9a41 wallet_api: add isDeterministic() (tobtoht)
def5819 wallet_api: add seed_offset param to seed() (tobtoht)
73959c6 wallet_api: store fee for incoming txs in history (Ben Evanoff)
712f362 wallet api: allow wallet to fetch all key images via api (benevanoff)
153d08d Allow tx note edits via TransactionHistory object in wallet/api (dsc)
2abd7b1 wallet_api: TransactionHistory - fill unconfirmed out payments dests (xiphon)
9a50bef Extend TransactionInfo with coinbase and description attributes in wallet/api (dsc)
22bb6a6 Allow AddressBook description edits via wallet/api interface (dsc)
This commit is contained in:
luigi1111 2021-05-12 16:55:38 -05:00
commit a080c0be9c
No known key found for this signature in database
GPG key ID: F4ACA0183641E010
9 changed files with 172 additions and 8 deletions

View file

@ -70,6 +70,25 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
return r; return r;
} }
bool AddressBookImpl::setDescription(std::size_t index, const std::string &description)
{
clearStatus();
const auto ab = m_wallet->m_wallet->get_address_book();
if (index >= ab.size()){
return false;
}
tools::wallet2::address_book_row entry = ab[index];
entry.m_description = description;
bool r = m_wallet->m_wallet->set_address_book_row(index, entry.m_address, NULL, entry.m_description, entry.m_is_subaddress);
if (r)
refresh();
else
m_errorCode = General_Error;
return r;
}
void AddressBookImpl::refresh() void AddressBookImpl::refresh()
{ {
LOG_PRINT_L2("Refreshing addressbook"); LOG_PRINT_L2("Refreshing addressbook");

View file

@ -45,6 +45,7 @@ public:
void refresh() override; void refresh() override;
std::vector<AddressBookRow*> getAll() const override; std::vector<AddressBookRow*> getAll() const override;
bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) override; bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) override;
bool setDescription(std::size_t index, const std::string &description) override;
bool deleteRow(std::size_t rowId) override; bool deleteRow(std::size_t rowId) override;
// Error codes. See AddressBook:ErrorCode enum in wallet2_api.h // Error codes. See AddressBook:ErrorCode enum in wallet2_api.h

View file

@ -92,6 +92,17 @@ std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const
return m_history; return m_history;
} }
void TransactionHistoryImpl::setTxNote(const std::string &txid, const std::string &note)
{
cryptonote::blobdata txid_data;
if(!epee::string_tools::parse_hexstr_to_binbuff(txid, txid_data) || txid_data.size() != sizeof(crypto::hash))
return;
const crypto::hash htxid = *reinterpret_cast<const crypto::hash*>(txid_data.data());
m_wallet->m_wallet->set_tx_note(htxid, note);
refresh();
}
void TransactionHistoryImpl::refresh() void TransactionHistoryImpl::refresh()
{ {
// multithreaded access: // multithreaded access:
@ -126,10 +137,13 @@ void TransactionHistoryImpl::refresh()
payment_id = payment_id.substr(0,16); payment_id = payment_id.substr(0,16);
TransactionInfoImpl * ti = new TransactionInfoImpl(); TransactionInfoImpl * ti = new TransactionInfoImpl();
ti->m_paymentid = payment_id; ti->m_paymentid = payment_id;
ti->m_coinbase = pd.m_coinbase;
ti->m_amount = pd.m_amount; ti->m_amount = pd.m_amount;
ti->m_fee = pd.m_fee;
ti->m_direction = TransactionInfo::Direction_In; ti->m_direction = TransactionInfo::Direction_In;
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
ti->m_blockheight = pd.m_block_height; ti->m_blockheight = pd.m_block_height;
ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash);
ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrIndex = { pd.m_subaddr_index.minor };
ti->m_subaddrAccount = pd.m_subaddr_index.major; ti->m_subaddrAccount = pd.m_subaddr_index.major;
ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index); ti->m_label = m_wallet->m_wallet->get_subaddress_label(pd.m_subaddr_index);
@ -173,6 +187,7 @@ void TransactionHistoryImpl::refresh()
ti->m_direction = TransactionInfo::Direction_Out; ti->m_direction = TransactionInfo::Direction_Out;
ti->m_hash = string_tools::pod_to_hex(hash); ti->m_hash = string_tools::pod_to_hex(hash);
ti->m_blockheight = pd.m_block_height; ti->m_blockheight = pd.m_block_height;
ti->m_description = m_wallet->m_wallet->get_tx_note(hash);
ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrIndex = pd.m_subaddr_indices;
ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_subaddrAccount = pd.m_subaddr_account;
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
@ -183,6 +198,7 @@ void TransactionHistoryImpl::refresh()
for (const auto &d: pd.m_dests) { for (const auto &d: pd.m_dests) {
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)}); ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
} }
m_history.push_back(ti); m_history.push_back(ti);
} }
@ -207,11 +223,16 @@ void TransactionHistoryImpl::refresh()
ti->m_failed = is_failed; ti->m_failed = is_failed;
ti->m_pending = true; ti->m_pending = true;
ti->m_hash = string_tools::pod_to_hex(hash); ti->m_hash = string_tools::pod_to_hex(hash);
ti->m_description = m_wallet->m_wallet->get_tx_note(hash);
ti->m_subaddrIndex = pd.m_subaddr_indices; ti->m_subaddrIndex = pd.m_subaddr_indices;
ti->m_subaddrAccount = pd.m_subaddr_account; ti->m_subaddrAccount = pd.m_subaddr_account;
ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : ""; ti->m_label = pd.m_subaddr_indices.size() == 1 ? m_wallet->m_wallet->get_subaddress_label({pd.m_subaddr_account, *pd.m_subaddr_indices.begin()}) : "";
ti->m_timestamp = pd.m_timestamp; ti->m_timestamp = pd.m_timestamp;
ti->m_confirmations = 0; ti->m_confirmations = 0;
for (const auto &d : pd.m_dests)
{
ti->m_transfers.push_back({d.amount, d.address(m_wallet->m_wallet->nettype(), pd.m_payment_id)});
}
m_history.push_back(ti); m_history.push_back(ti);
} }
@ -230,6 +251,7 @@ void TransactionHistoryImpl::refresh()
ti->m_direction = TransactionInfo::Direction_In; ti->m_direction = TransactionInfo::Direction_In;
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash); ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
ti->m_blockheight = pd.m_block_height; ti->m_blockheight = pd.m_block_height;
ti->m_description = m_wallet->m_wallet->get_tx_note(pd.m_tx_hash);
ti->m_pending = true; ti->m_pending = true;
ti->m_subaddrIndex = { pd.m_subaddr_index.minor }; ti->m_subaddrIndex = { pd.m_subaddr_index.minor };
ti->m_subaddrAccount = pd.m_subaddr_index.major; ti->m_subaddrAccount = pd.m_subaddr_index.major;

View file

@ -45,6 +45,7 @@ public:
virtual TransactionInfo * transaction(const std::string &id) const; virtual TransactionInfo * transaction(const std::string &id) const;
virtual std::vector<TransactionInfo*> getAll() const; virtual std::vector<TransactionInfo*> getAll() const;
virtual void refresh(); virtual void refresh();
virtual void setTxNote(const std::string &txid, const std::string &note);
private: private:

View file

@ -45,6 +45,7 @@ TransactionInfoImpl::TransactionInfoImpl()
: m_direction(Direction_Out) : m_direction(Direction_Out)
, m_pending(false) , m_pending(false)
, m_failed(false) , m_failed(false)
, m_coinbase(false)
, m_amount(0) , m_amount(0)
, m_fee(0) , m_fee(0)
, m_blockheight(0) , m_blockheight(0)
@ -77,6 +78,11 @@ bool TransactionInfoImpl::isFailed() const
return m_failed; return m_failed;
} }
bool TransactionInfoImpl::isCoinbase() const
{
return m_coinbase;
}
uint64_t TransactionInfoImpl::amount() const uint64_t TransactionInfoImpl::amount() const
{ {
return m_amount; return m_amount;
@ -92,6 +98,11 @@ uint64_t TransactionInfoImpl::blockHeight() const
return m_blockheight; return m_blockheight;
} }
std::string TransactionInfoImpl::description() const
{
return m_description;
}
std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const
{ {
return m_subaddrIndex; return m_subaddrIndex;

View file

@ -46,10 +46,12 @@ public:
//! true if hold //! true if hold
virtual bool isPending() const override; virtual bool isPending() const override;
virtual bool isFailed() const override; virtual bool isFailed() const override;
virtual bool isCoinbase() const override;
virtual uint64_t amount() const override; virtual uint64_t amount() const override;
//! always 0 for incoming txes //! always 0 for incoming txes
virtual uint64_t fee() const override; virtual uint64_t fee() const override;
virtual uint64_t blockHeight() const override; virtual uint64_t blockHeight() const override;
virtual std::string description() const override;
virtual std::set<uint32_t> subaddrIndex() const override; virtual std::set<uint32_t> subaddrIndex() const override;
virtual uint32_t subaddrAccount() const override; virtual uint32_t subaddrAccount() const override;
virtual std::string label() const override; virtual std::string label() const override;
@ -65,9 +67,11 @@ private:
int m_direction; int m_direction;
bool m_pending; bool m_pending;
bool m_failed; bool m_failed;
bool m_coinbase;
uint64_t m_amount; uint64_t m_amount;
uint64_t m_fee; uint64_t m_fee;
uint64_t m_blockheight; uint64_t m_blockheight;
std::string m_description;
std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers std::set<uint32_t> m_subaddrIndex; // always unique index for incoming transfers; can be multiple indices for outgoing transfers
uint32_t m_subaddrAccount; uint32_t m_subaddrAccount;
std::string m_label; std::string m_label;

View file

@ -791,11 +791,11 @@ bool WalletImpl::close(bool store)
return result; return result;
} }
std::string WalletImpl::seed() const std::string WalletImpl::seed(const std::string& seed_offset) const
{ {
epee::wipeable_string seed; epee::wipeable_string seed;
if (m_wallet) if (m_wallet)
m_wallet->get_seed(seed); m_wallet->get_seed(seed, seed_offset);
return std::string(seed.data(), seed.size()); // TODO return std::string(seed.data(), seed.size()); // TODO
} }
@ -1168,7 +1168,7 @@ bool WalletImpl::submitTransaction(const string &fileName) {
return true; return true;
} }
bool WalletImpl::exportKeyImages(const string &filename) bool WalletImpl::exportKeyImages(const string &filename, bool all)
{ {
if (m_wallet->watch_only()) if (m_wallet->watch_only())
{ {
@ -1178,7 +1178,7 @@ bool WalletImpl::exportKeyImages(const string &filename)
try try
{ {
if (!m_wallet->export_key_images(filename)) if (!m_wallet->export_key_images(filename), all)
{ {
setStatusError(tr("failed to save file ") + filename); setStatusError(tr("failed to save file ") + filename);
return false; return false;
@ -1216,6 +1216,68 @@ bool WalletImpl::importKeyImages(const string &filename)
return true; return true;
} }
bool WalletImpl::exportOutputs(const string &filename, bool all)
{
if (m_wallet->key_on_device())
{
setStatusError(string(tr("Not supported on HW wallets.")) + filename);
return false;
}
try
{
std::string data = m_wallet->export_outputs_to_str(all);
bool r = m_wallet->save_to_file(filename, data);
if (!r)
{
LOG_ERROR("Failed to save file " << filename);
setStatusError(string(tr("Failed to save file: ")) + filename);
return false;
}
}
catch (const std::exception &e)
{
LOG_ERROR("Error exporting outputs: " << e.what());
setStatusError(string(tr("Error exporting outputs: ")) + e.what());
return false;
}
LOG_PRINT_L2("Outputs exported to " << filename);
return true;
}
bool WalletImpl::importOutputs(const string &filename)
{
if (m_wallet->key_on_device())
{
setStatusError(string(tr("Not supported on HW wallets.")) + filename);
return false;
}
std::string data;
bool r = m_wallet->load_from_file(filename, data);
if (!r)
{
LOG_ERROR("Failed to read file: " << filename);
setStatusError(string(tr("Failed to read file: ")) + filename);
return false;
}
try
{
size_t n_outputs = m_wallet->import_outputs_from_str(data);
LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported");
}
catch (const std::exception &e)
{
LOG_ERROR("Failed to import outputs: " << e.what());
setStatusError(string(tr("Failed to import outputs: ")) + e.what());
return false;
}
return true;
}
void WalletImpl::addSubaddressAccount(const std::string& label) void WalletImpl::addSubaddressAccount(const std::string& label)
{ {
m_wallet->add_subaddress_account(label); m_wallet->add_subaddress_account(label);
@ -2104,6 +2166,11 @@ bool WalletImpl::watchOnly() const
return m_wallet->watch_only(); return m_wallet->watch_only();
} }
bool WalletImpl::isDeterministic() const
{
return m_wallet->is_deterministic();
}
void WalletImpl::clearStatus() const void WalletImpl::clearStatus() const
{ {
boost::lock_guard<boost::mutex> l(m_statusMutex); boost::lock_guard<boost::mutex> l(m_statusMutex);
@ -2305,6 +2372,10 @@ bool WalletImpl::rescanSpent()
return true; return true;
} }
void WalletImpl::setOffline(bool offline)
{
m_wallet->set_offline(offline);
}
void WalletImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const void WalletImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const
{ {

View file

@ -81,7 +81,7 @@ public:
const std::string &device_name); const std::string &device_name);
Device getDeviceType() const override; Device getDeviceType() const override;
bool close(bool store = true); bool close(bool store = true);
std::string seed() const override; std::string seed(const std::string& seed_offset = "") const override;
std::string getSeedLanguage() const override; std::string getSeedLanguage() const override;
void setSeedLanguage(const std::string &arg) override; void setSeedLanguage(const std::string &arg) override;
// void setListener(Listener *) {} // void setListener(Listener *) {}
@ -129,6 +129,7 @@ public:
void setRecoveringFromDevice(bool recoveringFromDevice) override; void setRecoveringFromDevice(bool recoveringFromDevice) override;
void setSubaddressLookahead(uint32_t major, uint32_t minor) override; void setSubaddressLookahead(uint32_t major, uint32_t minor) override;
bool watchOnly() const override; bool watchOnly() const override;
bool isDeterministic() const override;
bool rescanSpent() override; bool rescanSpent() override;
NetworkType nettype() const override {return static_cast<NetworkType>(m_wallet->nettype());} NetworkType nettype() const override {return static_cast<NetworkType>(m_wallet->nettype());}
void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override; void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override;
@ -164,8 +165,10 @@ public:
virtual PendingTransaction * createSweepUnmixableTransaction() override; virtual PendingTransaction * createSweepUnmixableTransaction() override;
bool submitTransaction(const std::string &fileName) override; bool submitTransaction(const std::string &fileName) override;
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override; virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
bool exportKeyImages(const std::string &filename) override; bool exportKeyImages(const std::string &filename, bool all = false) override;
bool importKeyImages(const std::string &filename) override; bool importKeyImages(const std::string &filename) override;
bool exportOutputs(const std::string &filename, bool all = false) override;
bool importOutputs(const std::string &filename) override;
virtual void disposeTransaction(PendingTransaction * t) override; virtual void disposeTransaction(PendingTransaction * t) override;
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations, virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
@ -181,6 +184,8 @@ public:
virtual bool setCacheAttribute(const std::string &key, const std::string &val) override; virtual bool setCacheAttribute(const std::string &key, const std::string &val) override;
virtual std::string getCacheAttribute(const std::string &key) const override; virtual std::string getCacheAttribute(const std::string &key) const override;
virtual void setOffline(bool offline) override;
virtual bool setUserNote(const std::string &txid, const std::string &note) override; virtual bool setUserNote(const std::string &txid, const std::string &note) override;
virtual std::string getUserNote(const std::string &txid) const override; virtual std::string getUserNote(const std::string &txid) const override;
virtual std::string getTxKey(const std::string &txid) const override; virtual std::string getTxKey(const std::string &txid) const override;

View file

@ -182,9 +182,11 @@ struct TransactionInfo
virtual int direction() const = 0; virtual int direction() const = 0;
virtual bool isPending() const = 0; virtual bool isPending() const = 0;
virtual bool isFailed() const = 0; virtual bool isFailed() const = 0;
virtual bool isCoinbase() const = 0;
virtual uint64_t amount() const = 0; virtual uint64_t amount() const = 0;
virtual uint64_t fee() const = 0; virtual uint64_t fee() const = 0;
virtual uint64_t blockHeight() const = 0; virtual uint64_t blockHeight() const = 0;
virtual std::string description() const = 0;
virtual std::set<uint32_t> subaddrIndex() const = 0; virtual std::set<uint32_t> subaddrIndex() const = 0;
virtual uint32_t subaddrAccount() const = 0; virtual uint32_t subaddrAccount() const = 0;
virtual std::string label() const = 0; virtual std::string label() const = 0;
@ -208,6 +210,7 @@ struct TransactionHistory
virtual TransactionInfo * transaction(const std::string &id) const = 0; virtual TransactionInfo * transaction(const std::string &id) const = 0;
virtual std::vector<TransactionInfo*> getAll() const = 0; virtual std::vector<TransactionInfo*> getAll() const = 0;
virtual void refresh() = 0; virtual void refresh() = 0;
virtual void setTxNote(const std::string &txid, const std::string &note) = 0;
}; };
/** /**
@ -250,6 +253,7 @@ struct AddressBook
virtual std::vector<AddressBookRow*> getAll() const = 0; virtual std::vector<AddressBookRow*> getAll() const = 0;
virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0; virtual bool addRow(const std::string &dst_addr , const std::string &payment_id, const std::string &description) = 0;
virtual bool deleteRow(std::size_t rowId) = 0; virtual bool deleteRow(std::size_t rowId) = 0;
virtual bool setDescription(std::size_t index, const std::string &description) = 0;
virtual void refresh() = 0; virtual void refresh() = 0;
virtual std::string errorString() const = 0; virtual std::string errorString() const = 0;
virtual int errorCode() const = 0; virtual int errorCode() const = 0;
@ -442,7 +446,7 @@ struct Wallet
}; };
virtual ~Wallet() = 0; virtual ~Wallet() = 0;
virtual std::string seed() const = 0; virtual std::string seed(const std::string& seed_offset = "") const = 0;
virtual std::string getSeedLanguage() const = 0; virtual std::string getSeedLanguage() const = 0;
virtual void setSeedLanguage(const std::string &arg) = 0; virtual void setSeedLanguage(const std::string &arg) = 0;
//! returns wallet status (Status_Ok | Status_Error) //! returns wallet status (Status_Ok | Status_Error)
@ -622,6 +626,12 @@ struct Wallet
*/ */
virtual bool watchOnly() const = 0; virtual bool watchOnly() const = 0;
/**
* @brief isDeterministic - checks if wallet keys are deterministic
* @return - true if deterministic
*/
virtual bool isDeterministic() const = 0;
/** /**
* @brief blockChainHeight - returns current blockchain height * @brief blockChainHeight - returns current blockchain height
* @return * @return
@ -897,9 +907,10 @@ struct Wallet
/*! /*!
* \brief exportKeyImages - exports key images to file * \brief exportKeyImages - exports key images to file
* \param filename * \param filename
* \param all - export all key images or only those that have not yet been exported
* \return - true on success * \return - true on success
*/ */
virtual bool exportKeyImages(const std::string &filename) = 0; virtual bool exportKeyImages(const std::string &filename, bool all = false) = 0;
/*! /*!
* \brief importKeyImages - imports key images from file * \brief importKeyImages - imports key images from file
@ -908,6 +919,19 @@ struct Wallet
*/ */
virtual bool importKeyImages(const std::string &filename) = 0; virtual bool importKeyImages(const std::string &filename) = 0;
/*!
* \brief importOutputs - exports outputs to file
* \param filename
* \return - true on success
*/
virtual bool exportOutputs(const std::string &filename, bool all = false) = 0;
/*!
* \brief importOutputs - imports outputs from file
* \param filename
* \return - true on success
*/
virtual bool importOutputs(const std::string &filename) = 0;
virtual TransactionHistory * history() = 0; virtual TransactionHistory * history() = 0;
virtual AddressBook * addressBook() = 0; virtual AddressBook * addressBook() = 0;
@ -1004,6 +1028,12 @@ struct Wallet
*/ */
virtual bool rescanSpent() = 0; virtual bool rescanSpent() = 0;
/*
* \brief setOffline - toggle set offline on/off
* \param offline - true/false
*/
virtual void setOffline(bool offline) = 0;
//! blackballs a set of outputs //! blackballs a set of outputs
virtual bool blackballOutputs(const std::vector<std::string> &outputs, bool add) = 0; virtual bool blackballOutputs(const std::vector<std::string> &outputs, bool add) = 0;