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:
commit
a080c0be9c
|
@ -70,6 +70,25 @@ bool AddressBookImpl::addRow(const std::string &dst_addr , const std::string &pa
|
|||
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()
|
||||
{
|
||||
LOG_PRINT_L2("Refreshing addressbook");
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
void refresh() 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 setDescription(std::size_t index, const std::string &description) override;
|
||||
bool deleteRow(std::size_t rowId) override;
|
||||
|
||||
// Error codes. See AddressBook:ErrorCode enum in wallet2_api.h
|
||||
|
|
|
@ -92,6 +92,17 @@ std::vector<TransactionInfo *> TransactionHistoryImpl::getAll() const
|
|||
return m_history;
|
||||
}
|
||||
|
||||
void TransactionHistoryImpl::setTxNote(const std::string &txid, const std::string ¬e)
|
||||
{
|
||||
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()
|
||||
{
|
||||
// multithreaded access:
|
||||
|
@ -126,10 +137,13 @@ void TransactionHistoryImpl::refresh()
|
|||
payment_id = payment_id.substr(0,16);
|
||||
TransactionInfoImpl * ti = new TransactionInfoImpl();
|
||||
ti->m_paymentid = payment_id;
|
||||
ti->m_coinbase = pd.m_coinbase;
|
||||
ti->m_amount = pd.m_amount;
|
||||
ti->m_fee = pd.m_fee;
|
||||
ti->m_direction = TransactionInfo::Direction_In;
|
||||
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
|
||||
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_subaddrAccount = pd.m_subaddr_index.major;
|
||||
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_hash = string_tools::pod_to_hex(hash);
|
||||
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_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()}) : "";
|
||||
|
@ -183,6 +198,7 @@ void TransactionHistoryImpl::refresh()
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -207,11 +223,16 @@ void TransactionHistoryImpl::refresh()
|
|||
ti->m_failed = is_failed;
|
||||
ti->m_pending = true;
|
||||
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_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_timestamp = pd.m_timestamp;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -230,6 +251,7 @@ void TransactionHistoryImpl::refresh()
|
|||
ti->m_direction = TransactionInfo::Direction_In;
|
||||
ti->m_hash = string_tools::pod_to_hex(pd.m_tx_hash);
|
||||
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_subaddrIndex = { pd.m_subaddr_index.minor };
|
||||
ti->m_subaddrAccount = pd.m_subaddr_index.major;
|
||||
|
|
|
@ -45,6 +45,7 @@ public:
|
|||
virtual TransactionInfo * transaction(const std::string &id) const;
|
||||
virtual std::vector<TransactionInfo*> getAll() const;
|
||||
virtual void refresh();
|
||||
virtual void setTxNote(const std::string &txid, const std::string ¬e);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ TransactionInfoImpl::TransactionInfoImpl()
|
|||
: m_direction(Direction_Out)
|
||||
, m_pending(false)
|
||||
, m_failed(false)
|
||||
, m_coinbase(false)
|
||||
, m_amount(0)
|
||||
, m_fee(0)
|
||||
, m_blockheight(0)
|
||||
|
@ -77,6 +78,11 @@ bool TransactionInfoImpl::isFailed() const
|
|||
return m_failed;
|
||||
}
|
||||
|
||||
bool TransactionInfoImpl::isCoinbase() const
|
||||
{
|
||||
return m_coinbase;
|
||||
}
|
||||
|
||||
uint64_t TransactionInfoImpl::amount() const
|
||||
{
|
||||
return m_amount;
|
||||
|
@ -92,6 +98,11 @@ uint64_t TransactionInfoImpl::blockHeight() const
|
|||
return m_blockheight;
|
||||
}
|
||||
|
||||
std::string TransactionInfoImpl::description() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
std::set<uint32_t> TransactionInfoImpl::subaddrIndex() const
|
||||
{
|
||||
return m_subaddrIndex;
|
||||
|
|
|
@ -46,10 +46,12 @@ public:
|
|||
//! true if hold
|
||||
virtual bool isPending() const override;
|
||||
virtual bool isFailed() const override;
|
||||
virtual bool isCoinbase() const override;
|
||||
virtual uint64_t amount() const override;
|
||||
//! always 0 for incoming txes
|
||||
virtual uint64_t fee() const override;
|
||||
virtual uint64_t blockHeight() const override;
|
||||
virtual std::string description() const override;
|
||||
virtual std::set<uint32_t> subaddrIndex() const override;
|
||||
virtual uint32_t subaddrAccount() const override;
|
||||
virtual std::string label() const override;
|
||||
|
@ -65,9 +67,11 @@ private:
|
|||
int m_direction;
|
||||
bool m_pending;
|
||||
bool m_failed;
|
||||
bool m_coinbase;
|
||||
uint64_t m_amount;
|
||||
uint64_t m_fee;
|
||||
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
|
||||
uint32_t m_subaddrAccount;
|
||||
std::string m_label;
|
||||
|
|
|
@ -791,11 +791,11 @@ bool WalletImpl::close(bool store)
|
|||
return result;
|
||||
}
|
||||
|
||||
std::string WalletImpl::seed() const
|
||||
std::string WalletImpl::seed(const std::string& seed_offset) const
|
||||
{
|
||||
epee::wipeable_string seed;
|
||||
if (m_wallet)
|
||||
m_wallet->get_seed(seed);
|
||||
m_wallet->get_seed(seed, seed_offset);
|
||||
return std::string(seed.data(), seed.size()); // TODO
|
||||
}
|
||||
|
||||
|
@ -1168,7 +1168,7 @@ bool WalletImpl::submitTransaction(const string &fileName) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::exportKeyImages(const string &filename)
|
||||
bool WalletImpl::exportKeyImages(const string &filename, bool all)
|
||||
{
|
||||
if (m_wallet->watch_only())
|
||||
{
|
||||
|
@ -1178,7 +1178,7 @@ bool WalletImpl::exportKeyImages(const string &filename)
|
|||
|
||||
try
|
||||
{
|
||||
if (!m_wallet->export_key_images(filename))
|
||||
if (!m_wallet->export_key_images(filename), all)
|
||||
{
|
||||
setStatusError(tr("failed to save file ") + filename);
|
||||
return false;
|
||||
|
@ -1216,6 +1216,68 @@ bool WalletImpl::importKeyImages(const string &filename)
|
|||
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)
|
||||
{
|
||||
m_wallet->add_subaddress_account(label);
|
||||
|
@ -2104,6 +2166,11 @@ bool WalletImpl::watchOnly() const
|
|||
return m_wallet->watch_only();
|
||||
}
|
||||
|
||||
bool WalletImpl::isDeterministic() const
|
||||
{
|
||||
return m_wallet->is_deterministic();
|
||||
}
|
||||
|
||||
void WalletImpl::clearStatus() const
|
||||
{
|
||||
boost::lock_guard<boost::mutex> l(m_statusMutex);
|
||||
|
@ -2305,6 +2372,10 @@ bool WalletImpl::rescanSpent()
|
|||
return true;
|
||||
}
|
||||
|
||||
void WalletImpl::setOffline(bool offline)
|
||||
{
|
||||
m_wallet->set_offline(offline);
|
||||
}
|
||||
|
||||
void WalletImpl::hardForkInfo(uint8_t &version, uint64_t &earliest_height) const
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ public:
|
|||
const std::string &device_name);
|
||||
Device getDeviceType() const override;
|
||||
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;
|
||||
void setSeedLanguage(const std::string &arg) override;
|
||||
// void setListener(Listener *) {}
|
||||
|
@ -129,6 +129,7 @@ public:
|
|||
void setRecoveringFromDevice(bool recoveringFromDevice) override;
|
||||
void setSubaddressLookahead(uint32_t major, uint32_t minor) override;
|
||||
bool watchOnly() const override;
|
||||
bool isDeterministic() const override;
|
||||
bool rescanSpent() override;
|
||||
NetworkType nettype() const override {return static_cast<NetworkType>(m_wallet->nettype());}
|
||||
void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override;
|
||||
|
@ -164,8 +165,10 @@ public:
|
|||
virtual PendingTransaction * createSweepUnmixableTransaction() override;
|
||||
bool submitTransaction(const std::string &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 exportOutputs(const std::string &filename, bool all = false) override;
|
||||
bool importOutputs(const std::string &filename) override;
|
||||
|
||||
virtual void disposeTransaction(PendingTransaction * t) override;
|
||||
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 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 ¬e) override;
|
||||
virtual std::string getUserNote(const std::string &txid) const override;
|
||||
virtual std::string getTxKey(const std::string &txid) const override;
|
||||
|
|
|
@ -182,9 +182,11 @@ struct TransactionInfo
|
|||
virtual int direction() const = 0;
|
||||
virtual bool isPending() const = 0;
|
||||
virtual bool isFailed() const = 0;
|
||||
virtual bool isCoinbase() const = 0;
|
||||
virtual uint64_t amount() const = 0;
|
||||
virtual uint64_t fee() const = 0;
|
||||
virtual uint64_t blockHeight() const = 0;
|
||||
virtual std::string description() const = 0;
|
||||
virtual std::set<uint32_t> subaddrIndex() const = 0;
|
||||
virtual uint32_t subaddrAccount() const = 0;
|
||||
virtual std::string label() const = 0;
|
||||
|
@ -208,6 +210,7 @@ struct TransactionHistory
|
|||
virtual TransactionInfo * transaction(const std::string &id) const = 0;
|
||||
virtual std::vector<TransactionInfo*> getAll() const = 0;
|
||||
virtual void refresh() = 0;
|
||||
virtual void setTxNote(const std::string &txid, const std::string ¬e) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -250,6 +253,7 @@ struct AddressBook
|
|||
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 deleteRow(std::size_t rowId) = 0;
|
||||
virtual bool setDescription(std::size_t index, const std::string &description) = 0;
|
||||
virtual void refresh() = 0;
|
||||
virtual std::string errorString() const = 0;
|
||||
virtual int errorCode() const = 0;
|
||||
|
@ -442,7 +446,7 @@ struct Wallet
|
|||
};
|
||||
|
||||
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 void setSeedLanguage(const std::string &arg) = 0;
|
||||
//! returns wallet status (Status_Ok | Status_Error)
|
||||
|
@ -622,6 +626,12 @@ struct Wallet
|
|||
*/
|
||||
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
|
||||
* @return
|
||||
|
@ -897,9 +907,10 @@ struct Wallet
|
|||
/*!
|
||||
* \brief exportKeyImages - exports key images to file
|
||||
* \param filename
|
||||
* \param all - export all key images or only those that have not yet been exported
|
||||
* \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
|
||||
|
@ -908,6 +919,19 @@ struct Wallet
|
|||
*/
|
||||
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 AddressBook * addressBook() = 0;
|
||||
|
@ -1003,6 +1027,12 @@ struct Wallet
|
|||
* \return true on success
|
||||
*/
|
||||
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
|
||||
virtual bool blackballOutputs(const std::vector<std::string> &outputs, bool add) = 0;
|
||||
|
|
Loading…
Reference in New Issue