Misc. wallet API and wallet2 changes
This commit is contained in:
parent
ce32e59844
commit
493608203f
|
@ -67,7 +67,10 @@ void SubaddressImpl::refresh(uint32_t accountIndex)
|
||||||
clearRows();
|
clearRows();
|
||||||
for (size_t i = 0; i < m_wallet->m_wallet->get_num_subaddresses(accountIndex); ++i)
|
for (size_t i = 0; i < m_wallet->m_wallet->get_num_subaddresses(accountIndex); ++i)
|
||||||
{
|
{
|
||||||
m_rows.push_back(new SubaddressRow(i, m_wallet->m_wallet->get_subaddress_as_str({accountIndex, (uint32_t)i}), m_wallet->m_wallet->get_subaddress_label({accountIndex, (uint32_t)i})));
|
m_rows.push_back(new SubaddressRow(i,
|
||||||
|
m_wallet->m_wallet->get_subaddress_as_str({accountIndex, (uint32_t)i}),
|
||||||
|
m_wallet->m_wallet->get_subaddress_label({accountIndex, (uint32_t)i}),
|
||||||
|
m_wallet->m_wallet->get_subaddress_used({accountIndex, (uint32_t)i})));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,6 +199,9 @@ void TransactionHistoryImpl::refresh()
|
||||||
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)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &r: pd.m_rings) {
|
||||||
|
ti->m_rings.push_back({string_tools::pod_to_hex(r.first), cryptonote::relative_output_offsets_to_absolute(r.second)});
|
||||||
|
}
|
||||||
m_history.push_back(ti);
|
m_history.push_back(ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,10 +232,15 @@ void TransactionHistoryImpl::refresh()
|
||||||
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)
|
|
||||||
|
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)});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto &r: pd.m_rings) {
|
||||||
|
ti->m_rings.push_back({string_tools::pod_to_hex(r.first), cryptonote::relative_output_offsets_to_absolute(r.second)});
|
||||||
|
}
|
||||||
m_history.push_back(ti);
|
m_history.push_back(ti);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -139,6 +139,11 @@ const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() c
|
||||||
return m_transfers;
|
return m_transfers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<std::pair<std::string, std::vector<uint64_t>>> &TransactionInfoImpl::rings() const
|
||||||
|
{
|
||||||
|
return m_rings;
|
||||||
|
}
|
||||||
|
|
||||||
uint64_t TransactionInfoImpl::confirmations() const
|
uint64_t TransactionInfoImpl::confirmations() const
|
||||||
{
|
{
|
||||||
return m_confirmations;
|
return m_confirmations;
|
||||||
|
|
|
@ -63,6 +63,8 @@ public:
|
||||||
virtual uint64_t confirmations() const override;
|
virtual uint64_t confirmations() const override;
|
||||||
virtual uint64_t unlockTime() const override;
|
virtual uint64_t unlockTime() const override;
|
||||||
|
|
||||||
|
virtual const std::vector<std::pair<std::string, std::vector<uint64_t>>> &rings() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_direction;
|
int m_direction;
|
||||||
bool m_pending;
|
bool m_pending;
|
||||||
|
@ -81,6 +83,7 @@ private:
|
||||||
std::vector<Transfer> m_transfers;
|
std::vector<Transfer> m_transfers;
|
||||||
uint64_t m_confirmations;
|
uint64_t m_confirmations;
|
||||||
uint64_t m_unlock_time;
|
uint64_t m_unlock_time;
|
||||||
|
std::vector<std::pair<std::string, std::vector<uint64_t>>> m_rings;
|
||||||
|
|
||||||
friend class TransactionHistoryImpl;
|
friend class TransactionHistoryImpl;
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "transaction_history.h"
|
#include "transaction_history.h"
|
||||||
#include "address_book.h"
|
#include "address_book.h"
|
||||||
#include "subaddress.h"
|
#include "subaddress.h"
|
||||||
|
#include "coins.h"
|
||||||
#include "subaddress_account.h"
|
#include "subaddress_account.h"
|
||||||
#include "common_defines.h"
|
#include "common_defines.h"
|
||||||
#include "common/util.h"
|
#include "common/util.h"
|
||||||
|
@ -166,11 +167,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||||
<< ", burnt: " << print_money(burnt)
|
<< ", burnt: " << print_money(burnt)
|
||||||
<< ", raw_output_value: " << print_money(amount)
|
<< ", raw_output_value: " << print_money(amount)
|
||||||
<< ", idx: " << subaddr_index);
|
<< ", idx: " << subaddr_index);
|
||||||
// do not signal on received tx if wallet is not syncronized completely
|
m_listener->moneyReceived(tx_hash, amount);
|
||||||
if (m_listener && m_wallet->synchronized()) {
|
m_listener->updated();
|
||||||
m_listener->moneyReceived(tx_hash, amount - burnt);
|
|
||||||
m_listener->updated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
|
virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
|
||||||
|
@ -182,11 +180,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||||
<< ", tx: " << tx_hash
|
<< ", tx: " << tx_hash
|
||||||
<< ", amount: " << print_money(amount)
|
<< ", amount: " << print_money(amount)
|
||||||
<< ", idx: " << subaddr_index);
|
<< ", idx: " << subaddr_index);
|
||||||
// do not signal on received tx if wallet is not syncronized completely
|
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
|
||||||
if (m_listener && m_wallet->synchronized()) {
|
m_listener->updated();
|
||||||
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
|
|
||||||
m_listener->updated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx,
|
virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx,
|
||||||
|
@ -198,11 +193,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
||||||
<< ", tx: " << tx_hash
|
<< ", tx: " << tx_hash
|
||||||
<< ", amount: " << print_money(amount)
|
<< ", amount: " << print_money(amount)
|
||||||
<< ", idx: " << subaddr_index);
|
<< ", idx: " << subaddr_index);
|
||||||
// do not signal on sent tx if wallet is not syncronized completely
|
m_listener->moneySpent(tx_hash, amount);
|
||||||
if (m_listener && m_wallet->synchronized()) {
|
m_listener->updated();
|
||||||
m_listener->moneySpent(tx_hash, amount);
|
|
||||||
m_listener->updated();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
|
virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
|
||||||
|
@ -436,6 +428,7 @@ WalletImpl::WalletImpl(NetworkType nettype, uint64_t kdf_rounds)
|
||||||
m_refreshEnabled = false;
|
m_refreshEnabled = false;
|
||||||
m_addressBook.reset(new AddressBookImpl(this));
|
m_addressBook.reset(new AddressBookImpl(this));
|
||||||
m_subaddress.reset(new SubaddressImpl(this));
|
m_subaddress.reset(new SubaddressImpl(this));
|
||||||
|
m_coins.reset(new CoinsImpl(this));
|
||||||
m_subaddressAccount.reset(new SubaddressAccountImpl(this));
|
m_subaddressAccount.reset(new SubaddressAccountImpl(this));
|
||||||
|
|
||||||
|
|
||||||
|
@ -763,6 +756,35 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c
|
||||||
return status() == Status_Ok;
|
return status() == Status_Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WalletImpl::recoverDeterministicWalletFromSpendKey(const std::string &path, const std::string &password, const std::string &language, const std::string &spendkey_string)
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
m_errorString.clear();
|
||||||
|
|
||||||
|
m_recoveringFromSeed = true;
|
||||||
|
m_recoveringFromDevice = false;
|
||||||
|
|
||||||
|
// parse spend key
|
||||||
|
crypto::secret_key spendkey;
|
||||||
|
if (!spendkey_string.empty()) {
|
||||||
|
cryptonote::blobdata spendkey_data;
|
||||||
|
if(!epee::string_tools::parse_hexstr_to_binbuff(spendkey_string, spendkey_data) || spendkey_data.size() != sizeof(crypto::secret_key))
|
||||||
|
{
|
||||||
|
setStatusError(tr("failed to parse secret spend key"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_wallet->generate(path, password, spendkey, true, false);
|
||||||
|
setSeedLanguage(language);
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
setStatusCritical(e.what());
|
||||||
|
}
|
||||||
|
return status() == Status_Ok;
|
||||||
|
}
|
||||||
|
|
||||||
bool WalletImpl::close(bool store)
|
bool WalletImpl::close(bool store)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1724,6 +1746,137 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PendingTransaction *WalletImpl::createTransactionSingle(const string &key_image, const string &dst_addr,
|
||||||
|
const size_t outputs, PendingTransaction::Priority priority)
|
||||||
|
{
|
||||||
|
clearStatus();
|
||||||
|
// Pause refresh thread while creating transaction
|
||||||
|
pauseRefresh();
|
||||||
|
|
||||||
|
cryptonote::address_parse_info info;
|
||||||
|
|
||||||
|
size_t fake_outs_count = m_wallet->adjust_mixin(m_wallet->default_mixin());
|
||||||
|
|
||||||
|
uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast<uint32_t>(priority));
|
||||||
|
|
||||||
|
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::vector<uint8_t> extra;
|
||||||
|
std::string extra_nonce;
|
||||||
|
vector<cryptonote::tx_destination_entry> dsts;
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
crypto::key_image ki;
|
||||||
|
if (!epee::string_tools::hex_to_pod(key_image, ki))
|
||||||
|
{
|
||||||
|
setStatusError(tr("failed to parse key image"));
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), dst_addr))
|
||||||
|
{
|
||||||
|
setStatusError(tr("Invalid destination address"));
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (info.has_payment_id) {
|
||||||
|
if (!extra_nonce.empty()) {
|
||||||
|
setStatusError(tr("a single transaction cannot use more than one payment id"));
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
|
||||||
|
}
|
||||||
|
if (error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!extra_nonce.empty() && !add_extra_nonce_to_tx_extra(extra, extra_nonce)) {
|
||||||
|
setStatusError(tr("failed to set up payment id, though it was decoded correctly"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
transaction->m_pending_tx = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress,
|
||||||
|
outputs, fake_outs_count, 0 /* unlock time */, priority, extra);
|
||||||
|
|
||||||
|
pendingTxPostProcess(transaction);
|
||||||
|
|
||||||
|
if (multisig().isMultisig) {
|
||||||
|
auto tx_set = m_wallet->make_multisig_tx_set(transaction->m_pending_tx);
|
||||||
|
transaction->m_pending_tx = tx_set.m_ptx;
|
||||||
|
transaction->m_signers = tx_set.m_signers;
|
||||||
|
}
|
||||||
|
} catch (const tools::error::daemon_busy&) {
|
||||||
|
// TODO: make it translatable with "tr"?
|
||||||
|
setStatusError(tr("daemon is busy. Please try again later."));
|
||||||
|
} catch (const tools::error::no_connection_to_daemon&) {
|
||||||
|
setStatusError(tr("no connection to daemon. Please make sure daemon is running."));
|
||||||
|
} catch (const tools::error::wallet_rpc_error& e) {
|
||||||
|
setStatusError(tr("RPC error: ") + e.to_string());
|
||||||
|
} catch (const tools::error::get_outs_error &e) {
|
||||||
|
setStatusError((boost::format(tr("failed to get outputs to mix: %s")) % e.what()).str());
|
||||||
|
} catch (const tools::error::not_enough_unlocked_money& e) {
|
||||||
|
std::ostringstream writer;
|
||||||
|
|
||||||
|
writer << boost::format(tr("not enough money to transfer, available only %s, sent amount %s")) %
|
||||||
|
print_money(e.available()) %
|
||||||
|
print_money(e.tx_amount());
|
||||||
|
setStatusError(writer.str());
|
||||||
|
} catch (const tools::error::not_enough_money& e) {
|
||||||
|
std::ostringstream writer;
|
||||||
|
|
||||||
|
writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) %
|
||||||
|
print_money(e.available()) %
|
||||||
|
print_money(e.tx_amount());
|
||||||
|
setStatusError(writer.str());
|
||||||
|
} catch (const tools::error::tx_not_possible& e) {
|
||||||
|
std::ostringstream writer;
|
||||||
|
|
||||||
|
writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) %
|
||||||
|
print_money(e.available()) %
|
||||||
|
print_money(e.tx_amount() + e.fee()) %
|
||||||
|
print_money(e.tx_amount()) %
|
||||||
|
print_money(e.fee());
|
||||||
|
setStatusError(writer.str());
|
||||||
|
} catch (const tools::error::not_enough_outs_to_mix& e) {
|
||||||
|
std::ostringstream writer;
|
||||||
|
writer << tr("not enough outputs for specified ring size") << " = " << (e.mixin_count() + 1) << ":";
|
||||||
|
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.");
|
||||||
|
setStatusError(writer.str());
|
||||||
|
} catch (const tools::error::tx_not_constructed&) {
|
||||||
|
setStatusError(tr("transaction was not constructed"));
|
||||||
|
} catch (const tools::error::tx_rejected& e) {
|
||||||
|
std::ostringstream writer;
|
||||||
|
writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
|
||||||
|
setStatusError(writer.str());
|
||||||
|
} catch (const tools::error::tx_sum_overflow& e) {
|
||||||
|
setStatusError(e.what());
|
||||||
|
} catch (const tools::error::zero_destination&) {
|
||||||
|
setStatusError(tr("one of destinations is zero"));
|
||||||
|
} catch (const tools::error::tx_too_big& e) {
|
||||||
|
setStatusError(tr("failed to find a suitable way to split transactions"));
|
||||||
|
} catch (const tools::error::transfer_error& e) {
|
||||||
|
setStatusError(string(tr("unknown transfer error: ")) + e.what());
|
||||||
|
} catch (const tools::error::wallet_internal_error& e) {
|
||||||
|
setStatusError(string(tr("internal error: ")) + e.what());
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
setStatusError(string(tr("unexpected error: ")) + e.what());
|
||||||
|
} catch (...) {
|
||||||
|
setStatusError(tr("unknown error"));
|
||||||
|
}
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
statusWithErrorString(transaction->m_status, transaction->m_errorString);
|
||||||
|
// Resume refresh thread
|
||||||
|
startRefresh();
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
|
PendingTransaction *WalletImpl::createSweepUnmixableTransaction()
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1843,6 +1996,11 @@ AddressBook *WalletImpl::addressBook()
|
||||||
return m_addressBook.get();
|
return m_addressBook.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Coins *WalletImpl::coins()
|
||||||
|
{
|
||||||
|
return m_coins.get();
|
||||||
|
}
|
||||||
|
|
||||||
Subaddress *WalletImpl::subaddress()
|
Subaddress *WalletImpl::subaddress()
|
||||||
{
|
{
|
||||||
return m_subaddress.get();
|
return m_subaddress.get();
|
||||||
|
|
|
@ -46,6 +46,7 @@ class PendingTransactionImpl;
|
||||||
class UnsignedTransactionImpl;
|
class UnsignedTransactionImpl;
|
||||||
class AddressBookImpl;
|
class AddressBookImpl;
|
||||||
class SubaddressImpl;
|
class SubaddressImpl;
|
||||||
|
class CoinsImpl;
|
||||||
class SubaddressAccountImpl;
|
class SubaddressAccountImpl;
|
||||||
struct Wallet2CallbackImpl;
|
struct Wallet2CallbackImpl;
|
||||||
class PendingTransactionInfoImpl;
|
class PendingTransactionInfoImpl;
|
||||||
|
@ -78,6 +79,10 @@ public:
|
||||||
const std::string &address_string,
|
const std::string &address_string,
|
||||||
const std::string &viewkey_string,
|
const std::string &viewkey_string,
|
||||||
const std::string &spendkey_string = "");
|
const std::string &spendkey_string = "");
|
||||||
|
bool recoverDeterministicWalletFromSpendKey(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &language,
|
||||||
|
const std::string &spendkey_string);
|
||||||
bool recoverFromDevice(const std::string &path,
|
bool recoverFromDevice(const std::string &path,
|
||||||
const std::string &password,
|
const std::string &password,
|
||||||
const std::string &device_name);
|
const std::string &device_name);
|
||||||
|
@ -164,6 +169,10 @@ public:
|
||||||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||||
uint32_t subaddr_account = 0,
|
uint32_t subaddr_account = 0,
|
||||||
std::set<uint32_t> subaddr_indices = {}) override;
|
std::set<uint32_t> subaddr_indices = {}) override;
|
||||||
|
|
||||||
|
PendingTransaction * createTransactionSingle(const std::string &key_image, const std::string &dst_addr,
|
||||||
|
size_t outputs = 1, PendingTransaction::Priority priority = PendingTransaction::Priority_Low) override;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -181,6 +190,7 @@ public:
|
||||||
PendingTransaction::Priority priority) const override;
|
PendingTransaction::Priority priority) const override;
|
||||||
virtual TransactionHistory * history() override;
|
virtual TransactionHistory * history() override;
|
||||||
virtual AddressBook * addressBook() override;
|
virtual AddressBook * addressBook() override;
|
||||||
|
virtual Coins * coins() override;
|
||||||
virtual Subaddress * subaddress() override;
|
virtual Subaddress * subaddress() override;
|
||||||
virtual SubaddressAccount * subaddressAccount() override;
|
virtual SubaddressAccount * subaddressAccount() override;
|
||||||
virtual void setListener(WalletListener * l) override;
|
virtual void setListener(WalletListener * l) override;
|
||||||
|
@ -252,6 +262,7 @@ private:
|
||||||
friend struct Wallet2CallbackImpl;
|
friend struct Wallet2CallbackImpl;
|
||||||
friend class AddressBookImpl;
|
friend class AddressBookImpl;
|
||||||
friend class SubaddressImpl;
|
friend class SubaddressImpl;
|
||||||
|
friend class CoinsImpl;
|
||||||
friend class SubaddressAccountImpl;
|
friend class SubaddressAccountImpl;
|
||||||
friend class PendingTransactionInfoImpl;
|
friend class PendingTransactionInfoImpl;
|
||||||
friend class TransactionConstructionInfoImpl;
|
friend class TransactionConstructionInfoImpl;
|
||||||
|
@ -265,6 +276,7 @@ private:
|
||||||
std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
|
std::unique_ptr<Wallet2CallbackImpl> m_wallet2Callback;
|
||||||
std::unique_ptr<AddressBookImpl> m_addressBook;
|
std::unique_ptr<AddressBookImpl> m_addressBook;
|
||||||
std::unique_ptr<SubaddressImpl> m_subaddress;
|
std::unique_ptr<SubaddressImpl> m_subaddress;
|
||||||
|
std::unique_ptr<CoinsImpl> m_coins;
|
||||||
std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
|
std::unique_ptr<SubaddressAccountImpl> m_subaddressAccount;
|
||||||
|
|
||||||
// multi-threaded refresh stuff
|
// multi-threaded refresh stuff
|
||||||
|
|
|
@ -250,6 +250,7 @@ struct TransactionInfo
|
||||||
virtual std::string paymentId() const = 0;
|
virtual std::string paymentId() const = 0;
|
||||||
//! only applicable for output transactions
|
//! only applicable for output transactions
|
||||||
virtual const std::vector<Transfer> & transfers() const = 0;
|
virtual const std::vector<Transfer> & transfers() const = 0;
|
||||||
|
virtual const std::vector<std::pair<std::string, std::vector<uint64_t>>> & rings() const = 0;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief The TransactionHistory - interface for displaying transaction history
|
* @brief The TransactionHistory - interface for displaying transaction history
|
||||||
|
@ -312,22 +313,66 @@ struct AddressBook
|
||||||
virtual int lookupPaymentID(const std::string &payment_id) const = 0;
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
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(int index) = 0;
|
||||||
|
virtual void thaw(int index) = 0;
|
||||||
|
virtual bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
struct SubaddressRow {
|
struct SubaddressRow {
|
||||||
public:
|
public:
|
||||||
SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label):
|
SubaddressRow(std::size_t _rowId, const std::string &_address, const std::string &_label, bool _used):
|
||||||
m_rowId(_rowId),
|
m_rowId(_rowId),
|
||||||
m_address(_address),
|
m_address(_address),
|
||||||
m_label(_label) {}
|
m_label(_label),
|
||||||
|
m_used(_used) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::size_t m_rowId;
|
std::size_t m_rowId;
|
||||||
std::string m_address;
|
std::string m_address;
|
||||||
std::string m_label;
|
std::string m_label;
|
||||||
|
bool m_used;
|
||||||
public:
|
public:
|
||||||
std::string extra;
|
std::string extra;
|
||||||
std::string getAddress() const {return m_address;}
|
std::string getAddress() const {return m_address;}
|
||||||
std::string getLabel() const {return m_label;}
|
std::string getLabel() const {return m_label;}
|
||||||
std::size_t getRowId() const {return m_rowId;}
|
std::size_t getRowId() const {return m_rowId;}
|
||||||
|
bool isUsed() const {return m_used;}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Subaddress
|
struct Subaddress
|
||||||
|
@ -915,6 +960,18 @@ struct Wallet
|
||||||
uint32_t subaddr_account = 0,
|
uint32_t subaddr_account = 0,
|
||||||
std::set<uint32_t> subaddr_indices = {}) = 0;
|
std::set<uint32_t> subaddr_indices = {}) = 0;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief createTransactionSingle creates transaction with single input
|
||||||
|
* \param key_image key image as string
|
||||||
|
* \param dst_addr destination address as string
|
||||||
|
* \param priority
|
||||||
|
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||||
|
* after object returned
|
||||||
|
*/
|
||||||
|
|
||||||
|
virtual PendingTransaction * createTransactionSingle(const std::string &key_image, const std::string &dst_addr,
|
||||||
|
size_t outputs = 1, PendingTransaction::Priority = PendingTransaction::Priority_Low) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
|
* \brief createSweepUnmixableTransaction creates transaction with unmixable outputs.
|
||||||
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||||
|
@ -1009,6 +1066,7 @@ struct Wallet
|
||||||
|
|
||||||
virtual TransactionHistory * history() = 0;
|
virtual TransactionHistory * history() = 0;
|
||||||
virtual AddressBook * addressBook() = 0;
|
virtual AddressBook * addressBook() = 0;
|
||||||
|
virtual Coins * coins() = 0;
|
||||||
virtual Subaddress * subaddress() = 0;
|
virtual Subaddress * subaddress() = 0;
|
||||||
virtual SubaddressAccount * subaddressAccount() = 0;
|
virtual SubaddressAccount * subaddressAccount() = 0;
|
||||||
virtual void setListener(WalletListener *) = 0;
|
virtual void setListener(WalletListener *) = 0;
|
||||||
|
@ -1065,7 +1123,8 @@ struct Wallet
|
||||||
/*
|
/*
|
||||||
* \brief signMessage - sign a message with the spend private key
|
* \brief signMessage - sign a message with the spend private key
|
||||||
* \param message - the message to sign (arbitrary byte data)
|
* \param message - the message to sign (arbitrary byte data)
|
||||||
* \return the signature
|
* \param address - the address to make the signature with, defaults to primary address (optional)
|
||||||
|
* \return the signature, empty string if the address is invalid or does not belong to the wallet
|
||||||
*/
|
*/
|
||||||
virtual std::string signMessage(const std::string &message, const std::string &address = "") = 0;
|
virtual std::string signMessage(const std::string &message, const std::string &address = "") = 0;
|
||||||
/*!
|
/*!
|
||||||
|
@ -1276,6 +1335,25 @@ struct WalletManager
|
||||||
return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString);
|
return createWalletFromKeys(path, password, language, testnet ? TESTNET : MAINNET, restoreHeight, addressString, viewKeyString, spendKeyString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief recover deterministic wallet from spend key.
|
||||||
|
* \param path Name of wallet file to be created
|
||||||
|
* \param password Password of wallet file
|
||||||
|
* \param language language
|
||||||
|
* \param nettype Network type
|
||||||
|
* \param restoreHeight restore from start height
|
||||||
|
* \param spendKeyString spend key
|
||||||
|
* \param kdf_rounds Number of rounds for key derivation function
|
||||||
|
* \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully)
|
||||||
|
*/
|
||||||
|
virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &language,
|
||||||
|
NetworkType nettype,
|
||||||
|
uint64_t restoreHeight,
|
||||||
|
const std::string &spendKeyString,
|
||||||
|
uint64_t kdf_rounds = 1) = 0;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \deprecated this method creates a wallet WITHOUT a passphrase, use createWalletFromKeys(..., password, ...) instead
|
* \deprecated this method creates a wallet WITHOUT a passphrase, use createWalletFromKeys(..., password, ...) instead
|
||||||
* \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted
|
* \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted
|
||||||
|
|
|
@ -127,6 +127,22 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Wallet *WalletManagerImpl::createDeterministicWalletFromSpendKey(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &language,
|
||||||
|
NetworkType nettype,
|
||||||
|
uint64_t restoreHeight,
|
||||||
|
const std::string &spendkey_string,
|
||||||
|
uint64_t kdf_rounds)
|
||||||
|
{
|
||||||
|
WalletImpl * wallet = new WalletImpl(nettype, kdf_rounds);
|
||||||
|
if(restoreHeight > 0){
|
||||||
|
wallet->setRefreshFromBlockHeight(restoreHeight);
|
||||||
|
}
|
||||||
|
wallet->recoverDeterministicWalletFromSpendKey(path, password, language, spendkey_string);
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
|
Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path,
|
||||||
const std::string &password,
|
const std::string &password,
|
||||||
NetworkType nettype,
|
NetworkType nettype,
|
||||||
|
|
|
@ -67,6 +67,13 @@ public:
|
||||||
const std::string &addressString,
|
const std::string &addressString,
|
||||||
const std::string &viewKeyString,
|
const std::string &viewKeyString,
|
||||||
const std::string &spendKeyString = "") override;
|
const std::string &spendKeyString = "") override;
|
||||||
|
virtual Wallet * createDeterministicWalletFromSpendKey(const std::string &path,
|
||||||
|
const std::string &password,
|
||||||
|
const std::string &language,
|
||||||
|
NetworkType nettype,
|
||||||
|
uint64_t restoreHeight,
|
||||||
|
const std::string &spendkey_string,
|
||||||
|
uint64_t kdf_rounds) override;
|
||||||
virtual Wallet * createWalletFromDevice(const std::string &path,
|
virtual Wallet * createWalletFromDevice(const std::string &path,
|
||||||
const std::string &password,
|
const std::string &password,
|
||||||
NetworkType nettype,
|
NetworkType nettype,
|
||||||
|
|
|
@ -193,7 +193,7 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height)
|
||||||
auto res = get_info();
|
auto res = get_info();
|
||||||
if (res)
|
if (res)
|
||||||
return res;
|
return res;
|
||||||
height = m_target_height;
|
height = m_target_height > m_height ? m_target_height : m_height;
|
||||||
return boost::optional<std::string>();
|
return boost::optional<std::string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1574,6 +1574,14 @@ void wallet2::add_subaddress_account(const std::string& label)
|
||||||
m_subaddress_labels[index_major][0] = label;
|
m_subaddress_labels[index_major][0] = label;
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
bool wallet2::get_subaddress_used(const cryptonote::subaddress_index& index)
|
||||||
|
{
|
||||||
|
return std::find_if(m_transfers.begin(), m_transfers.end(),
|
||||||
|
[this, index](const transfer_details &td) {
|
||||||
|
return td.m_subaddr_index == index;
|
||||||
|
}) != m_transfers.end();
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
|
void wallet2::add_subaddress(uint32_t index_major, const std::string& label)
|
||||||
{
|
{
|
||||||
THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
|
THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
|
||||||
|
@ -2459,13 +2467,14 @@ 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;
|
uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount;
|
||||||
if (!pool)
|
if (!pool)
|
||||||
{
|
{
|
||||||
m_transfers.push_back(transfer_details{});
|
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
|
||||||
transfer_details& td = m_transfers.back();
|
m_transfers.push_back(transfer_details{});
|
||||||
td.m_block_height = height;
|
transfer_details& td = m_transfers.back();
|
||||||
td.m_internal_output_index = o;
|
td.m_block_height = height;
|
||||||
td.m_global_output_index = o_indices[o];
|
td.m_internal_output_index = o;
|
||||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
td.m_global_output_index = o_indices[o];
|
||||||
td.m_txid = txid;
|
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||||
|
td.m_txid = txid;
|
||||||
td.m_key_image = tx_scan_info[o].ki;
|
td.m_key_image = tx_scan_info[o].ki;
|
||||||
td.m_key_image_known = !m_watch_only && !m_multisig;
|
td.m_key_image_known = !m_watch_only && !m_multisig;
|
||||||
if (!td.m_key_image_known)
|
if (!td.m_key_image_known)
|
||||||
|
@ -2562,12 +2571,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
uint64_t extra_amount = amount - burnt;
|
uint64_t extra_amount = amount - burnt;
|
||||||
if (!pool)
|
if (!pool)
|
||||||
{
|
{
|
||||||
|
boost::unique_lock<boost::shared_mutex> lock(m_transfers_mutex);
|
||||||
transfer_details &td = m_transfers[kit->second];
|
transfer_details &td = m_transfers[kit->second];
|
||||||
td.m_block_height = height;
|
td.m_block_height = height;
|
||||||
td.m_internal_output_index = o;
|
td.m_internal_output_index = o;
|
||||||
td.m_global_output_index = o_indices[o];
|
td.m_global_output_index = o_indices[o];
|
||||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||||
td.m_txid = txid;
|
td.m_txid = txid;
|
||||||
td.m_amount = amount;
|
td.m_amount = amount;
|
||||||
td.m_pk_index = pk_index - 1;
|
td.m_pk_index = pk_index - 1;
|
||||||
td.m_subaddr_index = tx_scan_info[o].received->index;
|
td.m_subaddr_index = tx_scan_info[o].received->index;
|
||||||
|
|
|
@ -1042,6 +1042,7 @@ private:
|
||||||
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) 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_address_as_str() const { return get_subaddress_as_str({0, 0}); }
|
||||||
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
|
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
|
||||||
|
bool get_subaddress_used(const cryptonote::subaddress_index& index);
|
||||||
void add_subaddress_account(const std::string& label);
|
void add_subaddress_account(const std::string& label);
|
||||||
size_t get_num_subaddress_accounts() const { return m_subaddress_labels.size(); }
|
size_t get_num_subaddress_accounts() const { return m_subaddress_labels.size(); }
|
||||||
size_t get_num_subaddresses(uint32_t index_major) const { return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; }
|
size_t get_num_subaddresses(uint32_t index_major) const { return index_major < m_subaddress_labels.size() ? m_subaddress_labels[index_major].size() : 0; }
|
||||||
|
@ -1713,6 +1714,7 @@ private:
|
||||||
|
|
||||||
static std::string get_default_daemon_address() { CRITICAL_REGION_LOCAL(default_daemon_address_lock); return default_daemon_address; }
|
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:
|
private:
|
||||||
/*!
|
/*!
|
||||||
* \brief Stores wallet information to wallet file.
|
* \brief Stores wallet information to wallet file.
|
||||||
|
|
Loading…
Reference in New Issue