Merge pull request 'Wowletify' (#396) from wowletify into master
Reviewed-on: https://git.wownero.com/wownero/wownero/pulls/396
This commit is contained in:
commit
ff5182f7f2
|
@ -35,12 +35,16 @@ set(wallet_api_sources
|
|||
wallet_manager.cpp
|
||||
transaction_info.cpp
|
||||
transaction_history.cpp
|
||||
transaction_construction_info.cpp
|
||||
pending_transaction_info.cpp
|
||||
pending_transaction.cpp
|
||||
utils.cpp
|
||||
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)
|
||||
|
@ -50,12 +54,16 @@ set(wallet_api_private_headers
|
|||
wallet_manager.h
|
||||
transaction_info.h
|
||||
transaction_history.h
|
||||
transaction_construction_info.h
|
||||
pending_transaction_info.h
|
||||
pending_transaction.h
|
||||
common_defines.h
|
||||
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})
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
#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);
|
||||
|
||||
m_rows.push_back(ci);
|
||||
}
|
||||
}
|
||||
|
||||
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(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);
|
||||
}
|
||||
|
||||
} // namespace
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef WOWLET_COINS_H
|
||||
#define WOWLET_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(int index) override;
|
||||
void thaw(int index) override;
|
||||
|
||||
bool isTransferUnlocked(uint64_t unlockTime, uint64_t blockHeight) override;
|
||||
|
||||
private:
|
||||
WalletImpl *m_wallet;
|
||||
std::vector<CoinsInfo*> m_rows;
|
||||
mutable boost::shared_mutex m_rowsMutex;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //WOWLET_COINS_H
|
|
@ -0,0 +1,118 @@
|
|||
#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;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Bitmonero = Monero;
|
|
@ -0,0 +1,67 @@
|
|||
#ifndef WOWLET_COINS_INFO_H
|
||||
#define WOWLET_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;
|
||||
|
||||
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;
|
||||
|
||||
friend class CoinsImpl;
|
||||
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif //WOWLET_COINS_INFO_H
|
|
@ -35,6 +35,7 @@
|
|||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "common/base58.h"
|
||||
#include "string_coding.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
@ -263,4 +264,50 @@ std::vector<std::string> PendingTransactionImpl::signersKeys() const {
|
|||
return keys;
|
||||
}
|
||||
|
||||
std::string PendingTransactionImpl::unsignedTxToBin() const {
|
||||
return m_wallet.m_wallet->dump_tx_to_str(m_pending_tx);
|
||||
}
|
||||
|
||||
std::string PendingTransactionImpl::unsignedTxToBase64() const {
|
||||
return epee::string_encoding::base64_encode(m_wallet.m_wallet->dump_tx_to_str(m_pending_tx));
|
||||
}
|
||||
|
||||
std::string PendingTransactionImpl::signedTxToHex(int index) const {
|
||||
auto index_ = static_cast<unsigned>(index);
|
||||
if (index < 0 || index_ >= m_pending_tx.size()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(m_pending_tx[index_].tx));
|
||||
}
|
||||
|
||||
size_t PendingTransactionImpl::signedTxSize(int index) const {
|
||||
auto index_ = static_cast<unsigned>(index);
|
||||
if (index < 0 || index_ >= m_pending_tx.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cryptonote::tx_to_blob(m_pending_tx[index_].tx).size();
|
||||
}
|
||||
|
||||
PendingTransactionInfo * PendingTransactionImpl::transaction(int index) const {
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
auto index_ = static_cast<unsigned>(index);
|
||||
return index_ < m_pending_tx_info.size() ? m_pending_tx_info[index_] : nullptr;
|
||||
}
|
||||
|
||||
void PendingTransactionImpl::refresh() {
|
||||
for (auto t : m_pending_tx_info)
|
||||
delete t;
|
||||
m_pending_tx_info.clear();
|
||||
|
||||
for (const auto& p : m_pending_tx)
|
||||
m_pending_tx_info.push_back(new PendingTransactionInfoImpl(m_wallet, p));
|
||||
}
|
||||
|
||||
std::vector<PendingTransactionInfo*> PendingTransactionImpl::getAll() const {
|
||||
return m_pending_tx_info;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "wallet/api/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "pending_transaction_info.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -53,6 +54,13 @@ public:
|
|||
uint64_t txCount() const override;
|
||||
std::vector<uint32_t> subaddrAccount() const override;
|
||||
std::vector<std::set<uint32_t>> subaddrIndices() const override;
|
||||
std::string unsignedTxToBin() const override;
|
||||
std::string unsignedTxToBase64() const override;
|
||||
std::string signedTxToHex(int index) const override;
|
||||
size_t signedTxSize(int index) const override;
|
||||
void refresh() override;
|
||||
std::vector<PendingTransactionInfo*> getAll() const override;
|
||||
PendingTransactionInfo * transaction(int index) const override;
|
||||
// TODO: continue with interface;
|
||||
|
||||
std::string multisigSignData() override;
|
||||
|
@ -66,6 +74,7 @@ private:
|
|||
int m_status;
|
||||
std::string m_errorString;
|
||||
std::vector<tools::wallet2::pending_tx> m_pending_tx;
|
||||
std::vector<PendingTransactionInfo*> m_pending_tx_info;
|
||||
std::unordered_set<crypto::public_key> m_signers;
|
||||
std::vector<std::string> m_tx_device_aux;
|
||||
std::vector<crypto::key_image> m_key_images;
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#include "pending_transaction_info.h"
|
||||
#include "transaction_construction_info.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Monero {
|
||||
|
||||
PendingTransactionInfo::~PendingTransactionInfo() = default;
|
||||
|
||||
PendingTransactionInfoImpl::PendingTransactionInfoImpl(WalletImpl &wallet, const tools::wallet2::pending_tx & ptx)
|
||||
: m_wallet(wallet)
|
||||
, m_ptx(ptx)
|
||||
, m_constructionData(new TransactionConstructionInfoImpl(wallet, ptx.construction_data))
|
||||
{
|
||||
}
|
||||
|
||||
PendingTransactionInfoImpl::~PendingTransactionInfoImpl() = default;
|
||||
|
||||
uint64_t PendingTransactionInfoImpl::fee() const
|
||||
{
|
||||
return m_ptx.fee;
|
||||
}
|
||||
|
||||
uint64_t PendingTransactionInfoImpl::dust() const
|
||||
{
|
||||
return m_ptx.dust;
|
||||
}
|
||||
|
||||
bool PendingTransactionInfoImpl::dustAddedToFee() const
|
||||
{
|
||||
return m_ptx.dust_added_to_fee;
|
||||
}
|
||||
|
||||
std::string PendingTransactionInfoImpl::txKey() const
|
||||
{
|
||||
return epee::string_tools::pod_to_hex(m_ptx.tx_key);
|
||||
}
|
||||
|
||||
TransactionConstructionInfo * PendingTransactionInfoImpl::constructionData() const {
|
||||
return m_constructionData;
|
||||
}
|
||||
|
||||
// TransactionConstructionInfo::Output TransactionConstructionInfoImpl::change() const {
|
||||
// return Output(
|
||||
// {m_ptx.change_dts.amount, m_ptx.change_dts.address(m_wallet.m_wallet->nettype(), crypto::hash())});
|
||||
// }
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#ifndef WOWLET_PENDING_TX_H
|
||||
#define WOWLET_PENDING_TX_H
|
||||
|
||||
#include "wallet/api/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "wallet.h"
|
||||
#include <string>
|
||||
|
||||
namespace Monero {
|
||||
|
||||
class PendingTransactionImpl;
|
||||
|
||||
class PendingTransactionInfoImpl : public PendingTransactionInfo
|
||||
{
|
||||
public:
|
||||
PendingTransactionInfoImpl(WalletImpl &wallet, const tools::wallet2::pending_tx & ptx);
|
||||
~PendingTransactionInfoImpl() override;
|
||||
|
||||
uint64_t fee() const override;
|
||||
uint64_t dust() const override;
|
||||
bool dustAddedToFee() const override;
|
||||
std::string txKey() const override;
|
||||
TransactionConstructionInfo *constructionData() const override;
|
||||
// Output change() const override;
|
||||
|
||||
private:
|
||||
friend class WalletImpl;
|
||||
WalletImpl &m_wallet;
|
||||
tools::wallet2::pending_tx m_ptx;
|
||||
TransactionConstructionInfo *m_constructionData;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif //FEATHER_PENDING_TX_H
|
|
@ -67,7 +67,10 @@ void SubaddressImpl::refresh(uint32_t accountIndex)
|
|||
clearRows();
|
||||
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})));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
#include "transaction_construction_info.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Monero {
|
||||
TransactionConstructionInfo::~TransactionConstructionInfo() = default;
|
||||
|
||||
TransactionConstructionInfo::Input::Input(uint64_t _amount, const std::string &_pubkey)
|
||||
: amount(_amount), pubkey(_pubkey) {}
|
||||
|
||||
TransactionConstructionInfo::Output::Output(uint64_t _amount, const std::string &_address)
|
||||
: amount(_amount), address(_address) {}
|
||||
|
||||
TransactionConstructionInfoImpl::TransactionConstructionInfoImpl(WalletImpl &wallet, const tools::wallet2::tx_construction_data & txcd)
|
||||
: m_wallet(wallet)
|
||||
, m_txcd(txcd) {}
|
||||
|
||||
TransactionConstructionInfoImpl::~TransactionConstructionInfoImpl() = default;
|
||||
|
||||
uint64_t TransactionConstructionInfoImpl::unlockTime() const {
|
||||
return m_txcd.unlock_time;
|
||||
}
|
||||
|
||||
std::set<std::uint32_t> TransactionConstructionInfoImpl::subaddressIndices() const {
|
||||
return m_txcd.subaddr_indices;
|
||||
}
|
||||
|
||||
std::vector<std::string> TransactionConstructionInfoImpl::subaddresses() const {
|
||||
std::vector<std::string> s;
|
||||
auto major = m_txcd.subaddr_account;
|
||||
for (const auto &minor : m_txcd.subaddr_indices) {
|
||||
s.push_back(m_wallet.m_wallet->get_subaddress_as_str({major, minor}));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
uint64_t TransactionConstructionInfoImpl::minMixinCount() const {
|
||||
uint64_t min_mixin = -1;
|
||||
for (const auto &source : m_txcd.sources) {
|
||||
size_t mixin = source.outputs.size() - 1;
|
||||
if (mixin < min_mixin)
|
||||
min_mixin = mixin;
|
||||
}
|
||||
|
||||
return min_mixin;
|
||||
}
|
||||
|
||||
std::vector<TransactionConstructionInfo::Input> TransactionConstructionInfoImpl::inputs() const {
|
||||
std::vector<Input> inputs;
|
||||
for (const auto &i : m_txcd.sources) {
|
||||
inputs.emplace_back(i.amount, epee::string_tools::pod_to_hex(i.real_out_tx_key));
|
||||
}
|
||||
return inputs;
|
||||
}
|
||||
|
||||
std::vector<TransactionConstructionInfo::Output> TransactionConstructionInfoImpl::outputs() const {
|
||||
std::vector<Output> outputs;
|
||||
for (const auto &o : m_txcd.splitted_dsts) {
|
||||
outputs.emplace_back(o.amount, o.address(m_wallet.m_wallet->nettype(), crypto::hash()));
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef WOWLET_TRANSACTION_CONSTRUCTION_INFO_H
|
||||
#define WOWLET_TRANSACTION_CONSTRUCTION_INFO_H
|
||||
|
||||
#include "wallet/api/wallet2_api.h"
|
||||
#include "wallet/wallet2.h"
|
||||
#include "wallet.h"
|
||||
#include <string>
|
||||
|
||||
namespace Monero {
|
||||
|
||||
class TransactionConstructionInfoImpl : public TransactionConstructionInfo
|
||||
{
|
||||
public:
|
||||
TransactionConstructionInfoImpl(WalletImpl &wallet, const tools::wallet2::tx_construction_data & ptx);
|
||||
~TransactionConstructionInfoImpl() override;
|
||||
|
||||
uint64_t unlockTime() const override;
|
||||
std::set<std::uint32_t> subaddressIndices() const override;
|
||||
std::vector<std::string> subaddresses() const override;
|
||||
uint64_t minMixinCount() const override;
|
||||
std::vector<Input> inputs() const override;
|
||||
std::vector<Output> outputs() const override;
|
||||
|
||||
private:
|
||||
friend class WalletImpl;
|
||||
WalletImpl &m_wallet;
|
||||
tools::wallet2::tx_construction_data m_txcd;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //WOWLET_TRANSACTION_CONSTRUCTION_INFO_H
|
|
@ -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)});
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -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_timestamp = pd.m_timestamp;
|
||||
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)});
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -266,3 +274,4 @@ void TransactionHistoryImpl::refresh()
|
|||
}
|
||||
|
||||
} // namespace
|
||||
}
|
|
@ -139,6 +139,11 @@ const std::vector<TransactionInfo::Transfer> &TransactionInfoImpl::transfers() c
|
|||
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
|
||||
{
|
||||
return m_confirmations;
|
||||
|
|
|
@ -63,6 +63,8 @@ public:
|
|||
virtual uint64_t confirmations() const override;
|
||||
virtual uint64_t unlockTime() const override;
|
||||
|
||||
virtual const std::vector<std::pair<std::string, std::vector<uint64_t>>> &rings() const override;
|
||||
|
||||
private:
|
||||
int m_direction;
|
||||
bool m_pending;
|
||||
|
@ -81,6 +83,7 @@ private:
|
|||
std::vector<Transfer> m_transfers;
|
||||
uint64_t m_confirmations;
|
||||
uint64_t m_unlock_time;
|
||||
std::vector<std::pair<std::string, std::vector<uint64_t>>> m_rings;
|
||||
|
||||
friend class TransactionHistoryImpl;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "unsigned_transaction.h"
|
||||
#include "wallet.h"
|
||||
#include "common_defines.h"
|
||||
#include "transaction_construction_info.h"
|
||||
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
|
@ -315,4 +316,24 @@ uint64_t UnsignedTransactionImpl::minMixinCount() const
|
|||
return min_mixin;
|
||||
}
|
||||
|
||||
TransactionConstructionInfo * UnsignedTransactionImpl::transaction(int index) const {
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
auto index_ = static_cast<unsigned>(index);
|
||||
return index_ < m_constructionInfo.size() ? m_constructionInfo[index_] : nullptr;
|
||||
}
|
||||
|
||||
void UnsignedTransactionImpl::refresh() {
|
||||
for (auto t : m_constructionInfo)
|
||||
delete t;
|
||||
m_constructionInfo.clear();
|
||||
|
||||
for (const auto& p : m_unsigned_tx_set.txes)
|
||||
m_constructionInfo.push_back(new TransactionConstructionInfoImpl(m_wallet, p));
|
||||
}
|
||||
|
||||
std::vector<TransactionConstructionInfo*> UnsignedTransactionImpl::getAll() const {
|
||||
return m_constructionInfo;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -55,6 +55,9 @@ public:
|
|||
bool sign(const std::string &signedFileName) override;
|
||||
std::string confirmationMessage() const override {return m_confirmationMessage;}
|
||||
uint64_t minMixinCount() const override;
|
||||
void refresh() override;
|
||||
std::vector<TransactionConstructionInfo*> getAll() const override;
|
||||
TransactionConstructionInfo * transaction(int index) const override;
|
||||
|
||||
private:
|
||||
// Callback function to check all loaded tx's and generate confirmationMessage
|
||||
|
@ -67,7 +70,7 @@ private:
|
|||
std::string m_errorString;
|
||||
tools::wallet2::unsigned_tx_set m_unsigned_tx_set;
|
||||
std::string m_confirmationMessage;
|
||||
std::vector<TransactionConstructionInfo*> m_constructionInfo;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -35,9 +35,11 @@
|
|||
#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"
|
||||
#include "string_coding.h"
|
||||
|
||||
#include "mnemonics/electrum-words.h"
|
||||
#include "mnemonics/english.h"
|
||||
|
@ -63,8 +65,8 @@ namespace {
|
|||
static const int MAX_REFRESH_INTERVAL_MILLIS = 1000 * 60 * 1;
|
||||
// Default refresh interval when connected to remote node
|
||||
static const int DEFAULT_REMOTE_NODE_REFRESH_INTERVAL_MILLIS = 1000 * 10;
|
||||
// Connection timeout 30 sec
|
||||
static const int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 1000 * 30;
|
||||
// Connection timeout 10 sec
|
||||
static const int DEFAULT_CONNECTION_TIMEOUT_MILLIS = 1000 * 10;
|
||||
|
||||
std::string get_default_ringdb_path(cryptonote::network_type nettype)
|
||||
{
|
||||
|
@ -163,11 +165,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||
<< ", tx: " << tx_hash
|
||||
<< ", amount: " << print_money(amount)
|
||||
<< ", idx: " << subaddr_index);
|
||||
// do not signal on received tx if wallet is not syncronized completely
|
||||
if (m_listener && m_wallet->synchronized()) {
|
||||
m_listener->moneyReceived(tx_hash, amount);
|
||||
m_listener->updated();
|
||||
}
|
||||
m_listener->moneyReceived(tx_hash, amount);
|
||||
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)
|
||||
|
@ -179,11 +178,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||
<< ", tx: " << tx_hash
|
||||
<< ", amount: " << print_money(amount)
|
||||
<< ", idx: " << subaddr_index);
|
||||
// do not signal on received tx if wallet is not syncronized completely
|
||||
if (m_listener && m_wallet->synchronized()) {
|
||||
m_listener->unconfirmedMoneyReceived(tx_hash, amount);
|
||||
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,
|
||||
|
@ -195,11 +191,8 @@ struct Wallet2CallbackImpl : public tools::i_wallet2_callback
|
|||
<< ", tx: " << tx_hash
|
||||
<< ", amount: " << print_money(amount)
|
||||
<< ", idx: " << subaddr_index);
|
||||
// do not signal on sent tx if wallet is not syncronized completely
|
||||
if (m_listener && m_wallet->synchronized()) {
|
||||
m_listener->moneySpent(tx_hash, amount);
|
||||
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)
|
||||
|
@ -433,15 +426,12 @@ 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));
|
||||
|
||||
|
||||
m_refreshIntervalMillis = DEFAULT_REFRESH_INTERVAL_MILLIS;
|
||||
|
||||
m_refreshThread = boost::thread([this] () {
|
||||
this->refreshThreadFunc();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
WalletImpl::~WalletImpl()
|
||||
|
@ -760,6 +750,35 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c
|
|||
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)
|
||||
{
|
||||
|
||||
|
@ -836,6 +855,11 @@ bool WalletImpl::setPassword(const std::string &password)
|
|||
return status() == Status_Ok;
|
||||
}
|
||||
|
||||
std::string WalletImpl::getPassword() const
|
||||
{
|
||||
return m_password;
|
||||
}
|
||||
|
||||
bool WalletImpl::setDevicePin(const std::string &pin)
|
||||
{
|
||||
clearStatus();
|
||||
|
@ -863,6 +887,27 @@ std::string WalletImpl::address(uint32_t accountIndex, uint32_t addressIndex) co
|
|||
return m_wallet->get_subaddress_as_str({accountIndex, addressIndex});
|
||||
}
|
||||
|
||||
bool WalletImpl::subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const
|
||||
{
|
||||
clearStatus();
|
||||
cryptonote::address_parse_info info;
|
||||
|
||||
if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), address)) {
|
||||
setStatusError(tr("Failed to parse address"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto i = m_wallet->get_subaddress_index(info.address);
|
||||
if (!i) {
|
||||
setStatusError(tr("Address doesn't belong to the wallet"));
|
||||
return false;
|
||||
}
|
||||
|
||||
index.first = i->major;
|
||||
index.second = i->minor;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WalletImpl::integratedAddress(const std::string &payment_id) const
|
||||
{
|
||||
crypto::hash8 pid;
|
||||
|
@ -1031,7 +1076,7 @@ uint64_t WalletImpl::daemonBlockChainHeight() const
|
|||
if(m_wallet->light_wallet()) {
|
||||
return m_wallet->get_light_wallet_scanned_block_height();
|
||||
}
|
||||
if (!m_is_connected)
|
||||
if (!m_is_connected && m_synchronized)
|
||||
return 0;
|
||||
std::string err;
|
||||
uint64_t result = m_wallet->get_daemon_blockchain_height(err);
|
||||
|
@ -1050,7 +1095,7 @@ uint64_t WalletImpl::daemonBlockChainTargetHeight() const
|
|||
if(m_wallet->light_wallet()) {
|
||||
return m_wallet->get_light_wallet_blockchain_height();
|
||||
}
|
||||
if (!m_is_connected)
|
||||
if (!m_is_connected && m_synchronized)
|
||||
return 0;
|
||||
std::string err;
|
||||
uint64_t result = m_wallet->get_daemon_blockchain_target_height(err);
|
||||
|
@ -1147,6 +1192,48 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
|
|||
return transaction;
|
||||
}
|
||||
|
||||
UnsignedTransaction *WalletImpl::loadUnsignedTxFromStr(const std::string &unsigned_tx) {
|
||||
clearStatus();
|
||||
|
||||
UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this);
|
||||
if (!m_wallet->parse_unsigned_tx_from_str(unsigned_tx, transaction->m_unsigned_tx_set)) {
|
||||
setStatusError(tr("Failed to load unsigned transactions"));
|
||||
transaction->m_status = UnsignedTransaction::Status::Status_Error;
|
||||
transaction->m_errorString = errorString();
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Check tx data and construct confirmation message
|
||||
std::string extra_message;
|
||||
if (!transaction->m_unsigned_tx_set.transfers.second.empty())
|
||||
extra_message = (boost::format("%u outputs to import. ") % (unsigned)transaction->m_unsigned_tx_set.transfers.second.size()).str();
|
||||
transaction->checkLoadedTx([&transaction](){return transaction->m_unsigned_tx_set.txes.size();}, [&transaction](size_t n)->const tools::wallet2::tx_construction_data&{return transaction->m_unsigned_tx_set.txes[n];}, extra_message);
|
||||
setStatus(transaction->status(), transaction->errorString());
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
UnsignedTransaction *WalletImpl::loadUnsignedTxFromBase64Str(const std::string &unsigned_tx_base64) {
|
||||
clearStatus();
|
||||
|
||||
std::string decoded_tx = epee::string_encoding::base64_decode(unsigned_tx_base64);
|
||||
|
||||
return this->loadUnsignedTxFromStr(decoded_tx);
|
||||
}
|
||||
|
||||
PendingTransaction *WalletImpl::loadSignedTx(const std::string &signed_filename) {
|
||||
clearStatus();
|
||||
PendingTransactionImpl * transaction = new PendingTransactionImpl(*this);
|
||||
|
||||
if (!m_wallet->load_tx(signed_filename, transaction->m_pending_tx)) {
|
||||
setStatusError(tr("Failed to load unsigned transactions"));
|
||||
return transaction;
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
bool WalletImpl::submitTransaction(const string &fileName) {
|
||||
clearStatus();
|
||||
std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this));
|
||||
|
@ -1175,7 +1262,7 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
|
|||
|
||||
try
|
||||
{
|
||||
if (!m_wallet->export_key_images(filename), all)
|
||||
if (!m_wallet->export_key_images(filename, all))
|
||||
{
|
||||
setStatusError(tr("failed to save file ") + filename);
|
||||
return false;
|
||||
|
@ -1275,6 +1362,91 @@ bool WalletImpl::importOutputs(const string &filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WalletImpl::importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_wallet->import_tx(txid, o_indices, height, block_version, ts, miner_tx, pool, double_spend_seen);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
LOG_ERROR("Failed to import transaction: " << e.what());
|
||||
setStatusError(string(tr("Failed to import transaction: ")) + e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WalletImpl::printBlockchain()
|
||||
{
|
||||
return m_wallet->printBlockchain();
|
||||
}
|
||||
std::string WalletImpl::printTransfers()
|
||||
{
|
||||
return m_wallet->printTransfers();
|
||||
}
|
||||
std::string WalletImpl::printPayments()
|
||||
{
|
||||
return m_wallet->printPayments();
|
||||
}
|
||||
std::string WalletImpl::printUnconfirmedPayments()
|
||||
{
|
||||
return m_wallet->printUnconfirmedPayments();
|
||||
}
|
||||
std::string WalletImpl::printConfirmedTransferDetails()
|
||||
{
|
||||
return m_wallet->printConfirmedTransferDetails();
|
||||
}
|
||||
std::string WalletImpl::printUnconfirmedTransferDetails()
|
||||
{
|
||||
return m_wallet->printUnconfirmedTransferDetails();
|
||||
}
|
||||
std::string WalletImpl::printPubKeys()
|
||||
{
|
||||
return m_wallet->printPubKeys();
|
||||
}
|
||||
std::string WalletImpl::printTxNotes()
|
||||
{
|
||||
return m_wallet->printTxNotes();
|
||||
}
|
||||
std::string WalletImpl::printSubaddresses()
|
||||
{
|
||||
return m_wallet->printSubaddresses();
|
||||
}
|
||||
std::string WalletImpl::printSubaddressLabels()
|
||||
{
|
||||
return m_wallet->printSubaddressLabels();
|
||||
}
|
||||
std::string WalletImpl::printAdditionalTxKeys()
|
||||
{
|
||||
return m_wallet->printAdditionalTxKeys();
|
||||
}
|
||||
std::string WalletImpl::printAttributes()
|
||||
{
|
||||
return m_wallet->printAttributes();
|
||||
}
|
||||
std::string WalletImpl::printKeyImages()
|
||||
{
|
||||
return m_wallet->printKeyImages();
|
||||
}
|
||||
std::string WalletImpl::printAccountTags()
|
||||
{
|
||||
return m_wallet->printAccountTags();
|
||||
}
|
||||
std::string WalletImpl::printTxKeys()
|
||||
{
|
||||
return m_wallet->printTxKeys();
|
||||
}
|
||||
std::string WalletImpl::printAddressBook()
|
||||
{
|
||||
return m_wallet->printAddressBook();
|
||||
}
|
||||
std::string WalletImpl::printScannedPoolTxs()
|
||||
{
|
||||
return m_wallet->printScannedPoolTxs();
|
||||
}
|
||||
|
||||
void WalletImpl::addSubaddressAccount(const std::string& label)
|
||||
{
|
||||
m_wallet->add_subaddress_account(label);
|
||||
|
@ -1652,6 +1824,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);
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
{
|
||||
|
@ -1755,6 +2058,7 @@ uint64_t WalletImpl::estimateTransactionFee(const std::vector<std::pair<std::str
|
|||
extra_size,
|
||||
m_wallet->use_fork_rules(8, 0),
|
||||
m_wallet->use_fork_rules(HF_VERSION_CLSAG, 0),
|
||||
true,
|
||||
m_wallet->get_base_fee(),
|
||||
m_wallet->get_fee_multiplier(m_wallet->adjust_priority(static_cast<uint32_t>(priority))),
|
||||
m_wallet->get_fee_quantization_mask());
|
||||
|
@ -1770,6 +2074,11 @@ AddressBook *WalletImpl::addressBook()
|
|||
return m_addressBook.get();
|
||||
}
|
||||
|
||||
Coins *WalletImpl::coins()
|
||||
{
|
||||
return m_coins.get();
|
||||
}
|
||||
|
||||
Subaddress *WalletImpl::subaddress()
|
||||
{
|
||||
return m_subaddress.get();
|
||||
|
@ -2238,37 +2547,34 @@ void WalletImpl::refreshThreadFunc()
|
|||
|
||||
void WalletImpl::doRefresh()
|
||||
{
|
||||
bool success = true;
|
||||
bool rescan = m_refreshShouldRescan.exchange(false);
|
||||
// synchronizing async and sync refresh calls
|
||||
boost::lock_guard<boost::mutex> guarg(m_refreshMutex2);
|
||||
do try {
|
||||
LOG_PRINT_L3(__FUNCTION__ << ": doRefresh, rescan = "<<rescan);
|
||||
// Syncing daemon and refreshing wallet simultaneously is very resource intensive.
|
||||
// Disable refresh if wallet is disconnected or daemon isn't synced.
|
||||
if (m_wallet->light_wallet() || daemonSynced()) {
|
||||
if(rescan)
|
||||
m_wallet->rescan_blockchain(false);
|
||||
m_wallet->refresh(trustedDaemon());
|
||||
if (!m_synchronized) {
|
||||
m_synchronized = true;
|
||||
}
|
||||
// assuming if we have empty history, it wasn't initialized yet
|
||||
// for further history changes client need to update history in
|
||||
// "on_money_received" and "on_money_sent" callbacks
|
||||
if (m_history->count() == 0) {
|
||||
m_history->refresh();
|
||||
}
|
||||
m_wallet->find_and_save_rings(false);
|
||||
} else {
|
||||
LOG_PRINT_L3(__FUNCTION__ << ": skipping refresh - daemon is not synced");
|
||||
if(rescan)
|
||||
m_wallet->rescan_blockchain(false);
|
||||
m_wallet->refresh(trustedDaemon());
|
||||
if (!m_synchronized) {
|
||||
m_synchronized = true;
|
||||
}
|
||||
// assuming if we have empty history, it wasn't initialized yet
|
||||
// for further history changes client need to update history in
|
||||
// "on_money_received" and "on_money_sent" callbacks
|
||||
if (m_history->count() == 0) {
|
||||
m_history->refresh();
|
||||
}
|
||||
m_wallet->find_and_save_rings(false);
|
||||
} catch (const std::exception &e) {
|
||||
success = false;
|
||||
setStatusError(e.what());
|
||||
break;
|
||||
}while(!rescan && (rescan=m_refreshShouldRescan.exchange(false))); // repeat if not rescanned and rescan was requested
|
||||
|
||||
m_is_connected = success;
|
||||
if (m_wallet2Callback->getListener()) {
|
||||
m_wallet2Callback->getListener()->refreshed();
|
||||
m_wallet2Callback->getListener()->refreshed(success);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2331,8 +2637,14 @@ void WalletImpl::pendingTxPostProcess(PendingTransactionImpl * pending)
|
|||
|
||||
bool WalletImpl::doInit(const string &daemon_address, const std::string &proxy_address, uint64_t upper_transaction_size_limit, bool ssl)
|
||||
{
|
||||
if (!m_wallet->init(daemon_address, m_daemon_login, proxy_address, upper_transaction_size_limit))
|
||||
return false;
|
||||
if (!m_wallet->init(daemon_address,
|
||||
m_daemon_login,
|
||||
proxy_address,
|
||||
upper_transaction_size_limit,
|
||||
trustedDaemon(),
|
||||
ssl ? epee::net_utils::ssl_support_t::e_ssl_support_autodetect : epee::net_utils::ssl_support_t::e_ssl_support_disabled)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// in case new wallet, this will force fast-refresh (pulling hashes instead of blocks)
|
||||
// If daemon isn't synced a calculated block height will be used instead
|
||||
|
|
|
@ -46,8 +46,11 @@ class PendingTransactionImpl;
|
|||
class UnsignedTransactionImpl;
|
||||
class AddressBookImpl;
|
||||
class SubaddressImpl;
|
||||
class CoinsImpl;
|
||||
class SubaddressAccountImpl;
|
||||
struct Wallet2CallbackImpl;
|
||||
class PendingTransactionInfoImpl;
|
||||
class TransactionConstructionInfoImpl;
|
||||
|
||||
class WalletImpl : public Wallet
|
||||
{
|
||||
|
@ -76,6 +79,10 @@ public:
|
|||
const std::string &address_string,
|
||||
const std::string &viewkey_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,
|
||||
const std::string &password,
|
||||
const std::string &device_name);
|
||||
|
@ -89,9 +96,11 @@ public:
|
|||
std::string errorString() const override;
|
||||
void statusWithErrorString(int& status, std::string& errorString) const override;
|
||||
bool setPassword(const std::string &password) override;
|
||||
std::string getPassword() const override;
|
||||
bool setDevicePin(const std::string &password) override;
|
||||
bool setDevicePassphrase(const std::string &password) override;
|
||||
std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const override;
|
||||
bool subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const override;
|
||||
std::string integratedAddress(const std::string &payment_id) const override;
|
||||
std::string secretViewKey() const override;
|
||||
std::string publicViewKey() const override;
|
||||
|
@ -162,19 +171,46 @@ public:
|
|||
PendingTransaction::Priority priority = PendingTransaction::Priority_Low,
|
||||
uint32_t subaddr_account = 0,
|
||||
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;
|
||||
bool submitTransaction(const std::string &fileName) override;
|
||||
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
|
||||
virtual UnsignedTransaction * loadUnsignedTxFromStr(const std::string &unsigned_tx) override;
|
||||
virtual UnsignedTransaction * loadUnsignedTxFromBase64Str(const std::string &unsigned_tx) override;
|
||||
virtual PendingTransaction * loadSignedTx(const std::string &signed_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;
|
||||
bool importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen) override;
|
||||
|
||||
virtual std::string printBlockchain() override;
|
||||
virtual std::string printTransfers() override;
|
||||
virtual std::string printPayments() override;
|
||||
virtual std::string printUnconfirmedPayments() override;
|
||||
virtual std::string printConfirmedTransferDetails() override;
|
||||
virtual std::string printUnconfirmedTransferDetails() override;
|
||||
virtual std::string printPubKeys() override;
|
||||
virtual std::string printTxNotes() override;
|
||||
virtual std::string printSubaddresses() override;
|
||||
virtual std::string printSubaddressLabels() override;
|
||||
virtual std::string printAdditionalTxKeys() override;
|
||||
virtual std::string printAttributes() override;
|
||||
virtual std::string printKeyImages() override;
|
||||
virtual std::string printAccountTags() override;
|
||||
virtual std::string printTxKeys() override;
|
||||
virtual std::string printAddressBook() override;
|
||||
virtual std::string printScannedPoolTxs() override;
|
||||
|
||||
virtual void disposeTransaction(PendingTransaction * t) override;
|
||||
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
|
||||
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;
|
||||
|
@ -244,7 +280,10 @@ private:
|
|||
friend struct Wallet2CallbackImpl;
|
||||
friend class AddressBookImpl;
|
||||
friend class SubaddressImpl;
|
||||
friend class CoinsImpl;
|
||||
friend class SubaddressAccountImpl;
|
||||
friend class PendingTransactionInfoImpl;
|
||||
friend class TransactionConstructionInfoImpl;
|
||||
|
||||
std::unique_ptr<tools::wallet2> m_wallet;
|
||||
mutable boost::mutex m_statusMutex;
|
||||
|
@ -255,6 +294,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
|
||||
|
|
|
@ -66,6 +66,47 @@ enum NetworkType : uint8_t {
|
|||
bool set;
|
||||
};
|
||||
|
||||
/*
|
||||
* @brief Transaction construction data
|
||||
*/
|
||||
struct TransactionConstructionInfo
|
||||
{
|
||||
struct Input {
|
||||
Input(uint64_t _amount, const std::string &_pubkey);
|
||||
const uint64_t amount;
|
||||
const std::string pubkey;
|
||||
};
|
||||
|
||||
struct Output {
|
||||
Output(uint64_t _amount, const std::string &_address);
|
||||
const uint64_t amount;
|
||||
const std::string address;
|
||||
};
|
||||
|
||||
virtual ~TransactionConstructionInfo() = 0;
|
||||
virtual uint64_t unlockTime() const = 0;
|
||||
virtual std::set<std::uint32_t> subaddressIndices() const = 0;
|
||||
virtual std::vector<std::string> subaddresses() const = 0;
|
||||
virtual uint64_t minMixinCount() const = 0;
|
||||
virtual std::vector<Input> inputs() const = 0;
|
||||
virtual std::vector<Output> outputs() const = 0;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* @brief Detailed pending transaction information
|
||||
*/
|
||||
struct PendingTransactionInfo
|
||||
{
|
||||
virtual ~PendingTransactionInfo() = 0;
|
||||
virtual uint64_t fee() const = 0;
|
||||
virtual uint64_t dust() const = 0;
|
||||
virtual bool dustAddedToFee() const = 0;
|
||||
virtual std::string txKey() const = 0;
|
||||
virtual TransactionConstructionInfo * constructionData() const = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Transaction-like interface for sending money
|
||||
*/
|
||||
|
@ -101,6 +142,13 @@ struct PendingTransaction
|
|||
virtual uint64_t txCount() const = 0;
|
||||
virtual std::vector<uint32_t> subaddrAccount() const = 0;
|
||||
virtual std::vector<std::set<uint32_t>> subaddrIndices() const = 0;
|
||||
virtual std::string unsignedTxToBin() const = 0;
|
||||
virtual std::string unsignedTxToBase64() const = 0;
|
||||
virtual std::string signedTxToHex(int index) const = 0;
|
||||
virtual size_t signedTxSize(int index) const = 0;
|
||||
virtual PendingTransactionInfo * transaction(int index) const = 0;
|
||||
virtual void refresh() = 0;
|
||||
virtual std::vector<PendingTransactionInfo*> getAll() const = 0;
|
||||
|
||||
/**
|
||||
* @brief multisigSignData
|
||||
|
@ -160,6 +208,9 @@ struct UnsignedTransaction
|
|||
* return - true on success
|
||||
*/
|
||||
virtual bool sign(const std::string &signedFileName) = 0;
|
||||
virtual void refresh() = 0;
|
||||
virtual std::vector<TransactionConstructionInfo*> getAll() const = 0;
|
||||
virtual TransactionConstructionInfo * transaction(int index) const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -198,6 +249,7 @@ struct TransactionInfo
|
|||
virtual std::string paymentId() const = 0;
|
||||
//! only applicable for output transactions
|
||||
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
|
||||
|
@ -260,22 +312,66 @@ 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;
|
||||
};
|
||||
|
||||
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 {
|
||||
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_address(_address),
|
||||
m_label(_label) {}
|
||||
m_label(_label),
|
||||
m_used(_used) {}
|
||||
|
||||
private:
|
||||
std::size_t m_rowId;
|
||||
std::string m_address;
|
||||
std::string m_label;
|
||||
bool m_used;
|
||||
public:
|
||||
std::string extra;
|
||||
std::string getAddress() const {return m_address;}
|
||||
std::string getLabel() const {return m_label;}
|
||||
std::size_t getRowId() const {return m_rowId;}
|
||||
bool isUsed() const {return m_used;}
|
||||
};
|
||||
|
||||
struct Subaddress
|
||||
|
@ -382,7 +478,7 @@ struct WalletListener
|
|||
/**
|
||||
* @brief refreshed - called when wallet refreshed by background thread or explicitly refreshed by calling "refresh" synchronously
|
||||
*/
|
||||
virtual void refreshed() = 0;
|
||||
virtual void refreshed(bool success) = 0;
|
||||
|
||||
/**
|
||||
* @brief called by device if the action is required
|
||||
|
@ -456,9 +552,11 @@ struct Wallet
|
|||
//! returns both error and error string atomically. suggested to use in instead of status() and errorString()
|
||||
virtual void statusWithErrorString(int& status, std::string& errorString) const = 0;
|
||||
virtual bool setPassword(const std::string &password) = 0;
|
||||
virtual std::string getPassword() const = 0;
|
||||
virtual bool setDevicePin(const std::string &pin) { (void)pin; return false; };
|
||||
virtual bool setDevicePassphrase(const std::string &passphrase) { (void)passphrase; return false; };
|
||||
virtual std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const = 0;
|
||||
virtual bool subaddressIndex(std::string address, std::pair<uint32_t, uint32_t> &index) const = 0;
|
||||
std::string mainAddress() const { return address(0, 0); }
|
||||
virtual std::string path() const = 0;
|
||||
virtual NetworkType nettype() const = 0;
|
||||
|
@ -868,6 +966,18 @@ struct Wallet
|
|||
uint32_t subaddr_account = 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.
|
||||
* \return PendingTransaction object. caller is responsible to check PendingTransaction::status()
|
||||
|
@ -882,7 +992,27 @@ struct Wallet
|
|||
* after object returned
|
||||
*/
|
||||
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;
|
||||
|
||||
|
||||
/*!
|
||||
* \brief loadUnsignedTx - creates transaction from unsigned tx string
|
||||
* \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status()
|
||||
* after object returned
|
||||
*/
|
||||
virtual UnsignedTransaction * loadUnsignedTxFromStr(const std::string &unsigned_tx) = 0;
|
||||
|
||||
/*!
|
||||
* \brief loadUnsignedTx - creates transaction from unsigned base64 encoded tx string
|
||||
* \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status()
|
||||
* after object returned
|
||||
*/
|
||||
virtual UnsignedTransaction * loadUnsignedTxFromBase64Str(const std::string &unsigned_tx_base64) = 0;
|
||||
|
||||
/*!
|
||||
* \brief loadSignedTx - creates transaction from signed tx file
|
||||
* \return - PendingTransaction object.
|
||||
*/
|
||||
virtual PendingTransaction * loadSignedTx(const std::string &signed_filename) = 0;
|
||||
|
||||
/*!
|
||||
* \brief submitTransaction - submits transaction in signed tx file
|
||||
* \return - true on success
|
||||
|
@ -933,8 +1063,29 @@ struct Wallet
|
|||
*/
|
||||
virtual bool importOutputs(const std::string &filename) = 0;
|
||||
|
||||
virtual bool importTransaction(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen) = 0;
|
||||
|
||||
virtual std::string printBlockchain() = 0;
|
||||
virtual std::string printTransfers() = 0;
|
||||
virtual std::string printPayments() = 0;
|
||||
virtual std::string printUnconfirmedPayments() = 0;
|
||||
virtual std::string printConfirmedTransferDetails() = 0;
|
||||
virtual std::string printUnconfirmedTransferDetails() = 0;
|
||||
virtual std::string printPubKeys() = 0;
|
||||
virtual std::string printTxNotes() = 0;
|
||||
virtual std::string printSubaddresses() = 0;
|
||||
virtual std::string printSubaddressLabels() = 0;
|
||||
virtual std::string printAdditionalTxKeys() = 0;
|
||||
virtual std::string printAttributes() = 0;
|
||||
virtual std::string printKeyImages() = 0;
|
||||
virtual std::string printAccountTags() = 0;
|
||||
virtual std::string printTxKeys() = 0;
|
||||
virtual std::string printAddressBook() = 0;
|
||||
virtual std::string printScannedPoolTxs() = 0;
|
||||
|
||||
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;
|
||||
|
@ -991,7 +1142,8 @@ struct Wallet
|
|||
/*
|
||||
* \brief signMessage - sign a message with the spend private key
|
||||
* \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;
|
||||
/*!
|
||||
|
@ -1200,6 +1352,25 @@ struct WalletManager
|
|||
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
|
||||
* \brief recovers existing wallet using keys. Creates a view only wallet if spend key is omitted
|
||||
|
|
|
@ -122,6 +122,22 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path,
|
|||
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,
|
||||
const std::string &password,
|
||||
NetworkType nettype,
|
||||
|
|
|
@ -67,6 +67,13 @@ public:
|
|||
const std::string &addressString,
|
||||
const std::string &viewKeyString,
|
||||
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,
|
||||
const std::string &password,
|
||||
NetworkType nettype,
|
||||
|
|
|
@ -51,7 +51,7 @@ using namespace epee;
|
|||
namespace tools
|
||||
{
|
||||
|
||||
static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
|
||||
static const std::chrono::seconds rpc_timeout = std::chrono::seconds(10);
|
||||
|
||||
NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::abstract_http_client &http_client, rpc_payment_state_t &rpc_payment_state, boost::recursive_mutex &mutex)
|
||||
: m_http_client(http_client)
|
||||
|
@ -162,7 +162,7 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height)
|
|||
auto res = get_info();
|
||||
if (res)
|
||||
return res;
|
||||
height = m_target_height;
|
||||
height = m_target_height > m_height ? m_target_height : m_height;
|
||||
return boost::optional<std::string>();
|
||||
}
|
||||
|
||||
|
|
|
@ -1537,6 +1537,14 @@ void wallet2::add_subaddress_account(const std::string& 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)
|
||||
{
|
||||
THROW_WALLET_EXCEPTION_IF(index_major >= m_subaddress_labels.size(), error::account_index_outofbound);
|
||||
|
@ -2169,13 +2177,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;
|
||||
if (!pool)
|
||||
{
|
||||
m_transfers.push_back(transfer_details{});
|
||||
transfer_details& td = m_transfers.back();
|
||||
td.m_block_height = height;
|
||||
td.m_internal_output_index = o;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||
td.m_txid = txid;
|
||||
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;
|
||||
td.m_internal_output_index = o;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
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_known = !m_watch_only && !m_multisig;
|
||||
if (!td.m_key_image_known)
|
||||
|
@ -2233,6 +2242,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1);
|
||||
}
|
||||
LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid);
|
||||
lock.unlock();
|
||||
|
||||
if (0 != m_callback)
|
||||
m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index, spends_one_of_ours(tx), td.m_tx.unlock_time);
|
||||
}
|
||||
|
@ -2271,12 +2282,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||
uint64_t extra_amount = amount - m_transfers[kit->second].amount();
|
||||
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;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||
td.m_txid = txid;
|
||||
td.m_block_height = height;
|
||||
td.m_internal_output_index = o;
|
||||
td.m_global_output_index = o_indices[o];
|
||||
td.m_tx = (const cryptonote::transaction_prefix&)tx;
|
||||
td.m_txid = txid;
|
||||
td.m_amount = amount;
|
||||
td.m_pk_index = pk_index - 1;
|
||||
td.m_subaddr_index = tx_scan_info[o].received->index;
|
||||
|
@ -3212,6 +3224,54 @@ void wallet2::update_pool_state(std::vector<std::tuple<cryptonote::transaction,
|
|||
}
|
||||
MTRACE("update_pool_state end");
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::import_tx(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen)
|
||||
{
|
||||
crypto::hash hash;
|
||||
epee::string_tools::hex_to_pod(txid, hash);
|
||||
|
||||
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::request req;
|
||||
cryptonote::COMMAND_RPC_GET_TRANSACTIONS::response res;
|
||||
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(hash));
|
||||
|
||||
req.decode_as_json = false;
|
||||
req.prune = true;
|
||||
|
||||
bool r;
|
||||
{
|
||||
const boost::lock_guard<boost::recursive_mutex> lock{m_daemon_rpc_mutex};
|
||||
uint64_t pre_call_credits = m_rpc_payment_state.credits;
|
||||
req.client = get_client_signature();
|
||||
r = epee::net_utils::invoke_http_json("/gettransactions", req, res, *m_http_client, rpc_timeout);
|
||||
if (r && res.status == CORE_RPC_STATUS_OK)
|
||||
check_rpc_cost("/gettransactions", res.credits, pre_call_credits, res.txs.size() * COST_PER_TX);
|
||||
}
|
||||
|
||||
MDEBUG("Got " << r << " and " << res.status);
|
||||
if (!(r && res.status == CORE_RPC_STATUS_OK)) {
|
||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Error calling gettransactions daemon RPC: r " + std::to_string(r) + ", status " + get_rpc_status(res.status));
|
||||
}
|
||||
|
||||
if (res.txs.size() != 1) {
|
||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Expected 1 tx, got " + std::to_string(res.txs.size()));
|
||||
}
|
||||
|
||||
const auto &tx_entry = res.txs[0];
|
||||
cryptonote::transaction tx;
|
||||
cryptonote::blobdata bd;
|
||||
crypto::hash tx_hash;
|
||||
|
||||
if (!get_pruned_tx(tx_entry, tx, tx_hash)) {
|
||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Failed to parse transaction from daemon");
|
||||
}
|
||||
|
||||
if (tx_hash != hash) {
|
||||
THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Got txid " + epee::string_tools::pod_to_hex(tx_hash) + " which we did not ask for");
|
||||
}
|
||||
|
||||
process_new_transaction(tx_hash, tx, o_indices, height, block_version, ts, miner_tx, pool, double_spend_seen, {});
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::process_pool_state(const std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &txs)
|
||||
{
|
||||
|
@ -3235,11 +3295,19 @@ void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height,
|
|||
{
|
||||
std::vector<crypto::hash> hashes;
|
||||
|
||||
const uint64_t checkpoint_height = m_checkpoints.get_max_height();
|
||||
// Get highest checkpoint that is lower than stop_height
|
||||
uint64_t checkpoint_height = 0;
|
||||
for (auto i : m_checkpoints.get_points()) {
|
||||
if (i.first > stop_height) {
|
||||
break;
|
||||
}
|
||||
checkpoint_height = i.first;
|
||||
}
|
||||
|
||||
if ((stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) && !force)
|
||||
{
|
||||
// we will drop all these, so don't bother getting them
|
||||
uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size();
|
||||
uint64_t missing_blocks = checkpoint_height - m_blockchain.size();
|
||||
while (missing_blocks-- > 0)
|
||||
m_blockchain.push_back(crypto::null_hash); // maybe a bit suboptimal, but deque won't do huge reallocs like vector
|
||||
m_blockchain.push_back(m_checkpoints.get_points().at(checkpoint_height));
|
||||
|
@ -5504,6 +5572,315 @@ void wallet2::write_watch_only_wallet(const std::string& wallet_name, const epee
|
|||
bool r = store_keys(new_keys_filename, password, true);
|
||||
THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, new_keys_filename);
|
||||
}
|
||||
|
||||
std::string wallet2::printBlockchain()
|
||||
{
|
||||
std::string blstr;
|
||||
blstr += "offset: " + std::to_string(m_blockchain.offset()) + "\n";
|
||||
blstr += "genesis: " + string_tools::pod_to_hex(m_blockchain.genesis()) + "\n";
|
||||
|
||||
for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); i++) {
|
||||
blstr += std::to_string(i) + " : " + string_tools::pod_to_hex(m_blockchain[i]) + "\n";
|
||||
}
|
||||
|
||||
return blstr;
|
||||
}
|
||||
|
||||
std::string wallet2::printTransfers()
|
||||
{
|
||||
std::string str;
|
||||
for (const auto &td : m_transfers) {
|
||||
str += "block_height: " + std::to_string(td.m_block_height) + "\n";
|
||||
str += printTxPrefix(td.m_tx);
|
||||
str += "txid: " + string_tools::pod_to_hex(td.m_txid) + "\n";
|
||||
str += "internal_output_index: " + std::to_string(td.m_internal_output_index) + "\n";
|
||||
str += "global_output_index: " + std::to_string(td.m_global_output_index) + "\n";
|
||||
str += "spent: " + std::to_string(td.m_spent) + "\n";
|
||||
str += "frozen: " + std::to_string(td.m_frozen) + "\n";
|
||||
str += "spent_height: " + std::to_string(td.m_spent_height) + "\n";
|
||||
str += "key_image: " + string_tools::pod_to_hex(td.m_key_image) + "\n";
|
||||
str += "mask: " + string_tools::pod_to_hex(td.m_mask) + "\n";
|
||||
str += "amount: " + std::to_string(td.m_amount) + "\n";
|
||||
str += "rct: " + std::to_string(td.m_rct) + "\n";
|
||||
str += "key_image_known: " + std::to_string(td.m_key_image_known) + "\n";
|
||||
str += "key_image_request: " + std::to_string(td.m_key_image_request) + "\n";
|
||||
str += "pk_index: " + std::to_string(td.m_pk_index) + "\n";
|
||||
str += "subaddr_index: " + std::to_string(td.m_subaddr_index.major) + "," + std::to_string(td.m_subaddr_index.minor) + "\n";
|
||||
str += "key_image_partial: " + std::to_string(td.m_key_image_partial) + "\n";
|
||||
str += "multisig_k:\n";
|
||||
for (const auto &el : td.m_multisig_k) {
|
||||
str += " " + string_tools::pod_to_hex(el) + "\n";
|
||||
}
|
||||
|
||||
str += "multisig_info:\n";
|
||||
for (const auto &el : td.m_multisig_info) {
|
||||
str += " signer: " + string_tools::pod_to_hex(el.m_signer) + "\n";
|
||||
str += " LR:\n";
|
||||
for (const auto &em : el.m_LR) {
|
||||
str += " L: " + string_tools::pod_to_hex(em.m_L) + "\n";
|
||||
str += " R: " + string_tools::pod_to_hex(em.m_R) + "\n";
|
||||
}
|
||||
str += "\n";
|
||||
str += " partial_key_images:\n";
|
||||
for (const auto &em : el.m_partial_key_images) {
|
||||
str += " " + string_tools::pod_to_hex(em) + "\n";
|
||||
}
|
||||
str += "\n";
|
||||
}
|
||||
|
||||
str += "uses:\n";
|
||||
for (const auto &el : td.m_uses) {
|
||||
str += " " + std::to_string(el.first) + " : " + string_tools::pod_to_hex(el.second) + "\n";
|
||||
}
|
||||
str += "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printUnconfirmedPayments()
|
||||
{
|
||||
std::string str;
|
||||
for (const auto &el : m_unconfirmed_payments) {
|
||||
auto ppd = el.second;
|
||||
str += "double_spend_seen: " + std::to_string(ppd.m_double_spend_seen) + "\n";
|
||||
str += printPaymentDetails(ppd.m_pd);
|
||||
str += "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printConfirmedTransferDetails()
|
||||
{
|
||||
std::string str;
|
||||
for (const auto &el : m_confirmed_txs) {
|
||||
auto ctd = el.second;
|
||||
str += "amount_in: " + std::to_string(ctd.m_amount_in) + "\n";
|
||||
str += "amount_out: " + std::to_string(ctd.m_amount_out) + "\n";
|
||||
str += "change: " + std::to_string(ctd.m_change) + "\n";
|
||||
str += "block_height: " + std::to_string(ctd.m_block_height) + "\n";
|
||||
str += "dests:\n";
|
||||
for (const auto &em : ctd.m_dests) {
|
||||
str += printTxDestinationEntry(em);
|
||||
}
|
||||
str += "payment_id: " + string_tools::pod_to_hex(ctd.m_payment_id) + "\n";
|
||||
str += "timestamp: " + std::to_string(ctd.m_timestamp) + "\n";
|
||||
str += "unlock_time: " + std::to_string(ctd.m_unlock_time) + "\n";
|
||||
str += "subaddr_account: " + std::to_string(ctd.m_subaddr_account) + "\n";
|
||||
str += "subaddr_indices: ";
|
||||
for (auto em : ctd.m_subaddr_indices) {
|
||||
str += std::to_string(em);
|
||||
}
|
||||
str += "\n\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printUnconfirmedTransferDetails()
|
||||
{
|
||||
std::string str;
|
||||
for (const auto &el : m_unconfirmed_txs) {
|
||||
auto utd = el.second;
|
||||
str += printTxPrefix(utd.m_tx);
|
||||
str += "amount_in: " + std::to_string(utd.m_amount_in) + "\n";
|
||||
str += "amount_out: " + std::to_string(utd.m_amount_out) + "\n";
|
||||
str += "change: " + std::to_string(utd.m_change) + "\n";
|
||||
str += "sent_time: " + std::to_string(utd.m_sent_time) + "\n";
|
||||
str += "dests:\n";
|
||||
for (const auto &em : utd.m_dests) {
|
||||
str += printTxDestinationEntry(em);
|
||||
}
|
||||
str += "payment_id: " + string_tools::pod_to_hex(utd.m_payment_id) + "\n";
|
||||
str += "timestamp: " + std::to_string(utd.m_timestamp) + "\n";
|
||||
str += "subaddr_account: " + std::to_string(utd.m_subaddr_account) + "\n";
|
||||
str += "subaddr_indices: ";
|
||||
for (auto em : utd.m_subaddr_indices) {
|
||||
str += std::to_string(em);
|
||||
}
|
||||
str += "\n\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printPayments()
|
||||
{
|
||||
std::string str;
|
||||
for (const auto &el : m_payments) {
|
||||
str += printPaymentDetails(el.second) + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printPubKeys()
|
||||
{
|
||||
std::string str;
|
||||
vector<std::pair<crypto::public_key, size_t>> v;
|
||||
for (const auto &el : m_pub_keys) {
|
||||
v.push_back(el);
|
||||
}
|
||||
std::sort(v.begin(), v.end(),
|
||||
[](std::pair<crypto::public_key, size_t> a, std::pair<crypto::public_key, size_t> b){return a.second < b.second;});
|
||||
for (const auto &el : v){
|
||||
str += string_tools::pod_to_hex(el.first) + " : " + boost::to_string(el.second) + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printTxNotes()
|
||||
{
|
||||
std::string str;
|
||||
for (std::pair<crypto::hash, std::string> el : m_tx_notes) {
|
||||
str += string_tools::pod_to_hex(el.first) + " : " + el.second + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printSubaddresses()
|
||||
{
|
||||
std::string str;
|
||||
vector<std::pair<crypto::public_key, cryptonote::subaddress_index>> v;
|
||||
for (const auto &el : m_subaddresses) {
|
||||
v.push_back(el);
|
||||
}
|
||||
std::sort(v.begin(), v.end(), [](std::pair<crypto::public_key, cryptonote::subaddress_index> a, std::pair<crypto::public_key, cryptonote::subaddress_index> b) {
|
||||
if (a.second.major == b.second.major) {
|
||||
return a.second.minor < b.second.minor;
|
||||
}
|
||||
return a.second.major < b.second.major;
|
||||
});
|
||||
for (const auto &el : v) {
|
||||
str += string_tools::pod_to_hex(el.first) + " : " + std::to_string(el.second.major) + "," + std::to_string(el.second.minor) + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printSubaddressLabels()
|
||||
{
|
||||
std::string str;
|
||||
for (size_t i = 0; i < m_subaddress_labels.size(); i++) {
|
||||
for (size_t j = 0; j < m_subaddress_labels[i].size(); j++) {
|
||||
str += std::to_string(i) + "," + std::to_string(j) + " : " + m_subaddress_labels[i][j] + "\n";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printAdditionalTxKeys()
|
||||
{
|
||||
std::string str;
|
||||
for (std::pair<crypto::hash, std::vector<crypto::secret_key>> el : m_additional_tx_keys) {
|
||||
str += "Txid: " + string_tools::pod_to_hex(el.first) + " (" + std::to_string(el.second.size()) + ")\n";
|
||||
for (auto em : el.second) {
|
||||
str += " " + string_tools::pod_to_hex(em) + "\n";
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printAttributes()
|
||||
{
|
||||
std::string str;
|
||||
for (auto el : m_attributes) {
|
||||
str += el.first + " : " + el.second + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printKeyImages()
|
||||
{
|
||||
std::string str;
|
||||
vector<std::pair<crypto::key_image, size_t>> v;
|
||||
for (const auto &el : m_key_images) {
|
||||
v.push_back(el);
|
||||
}
|
||||
std::sort(v.begin(), v.end(), [](std::pair<crypto::key_image, size_t> a, std::pair<crypto::key_image, size_t> b){return a.second < b.second;});
|
||||
for (const auto &el: v) {
|
||||
str += string_tools::pod_to_hex(el.first) + " : " + boost::to_string(el.second) + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printAccountTags()
|
||||
{
|
||||
std::string str;
|
||||
for (size_t i = 0; i < m_account_tags.second.size(); i++) {
|
||||
str += std::to_string(i) + " : " + m_account_tags.second[i] + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printTxKeys()
|
||||
{
|
||||
std::string str;
|
||||
for (std::pair<crypto::hash, crypto::secret_key> el : m_tx_keys) {
|
||||
str += string_tools::pod_to_hex(el.first) + " : " + string_tools::pod_to_hex(el.second) + "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printAddressBook()
|
||||
{
|
||||
std::string str;
|
||||
for (auto el : m_address_book) {
|
||||
str += "address: " + string_tools::pod_to_hex(el.m_address) + "\n";
|
||||
str += "payment_id: " + string_tools::pod_to_hex(el.m_payment_id) + "\n";
|
||||
str += "description: " + el.m_description + "\n";
|
||||
str += "is_subaddress: " + std::to_string(el.m_is_subaddress) + "\n";
|
||||
str += "has_payment_id: " + std::to_string(el.m_has_payment_id) + "\n";
|
||||
str += "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printScannedPoolTxs()
|
||||
{
|
||||
std::string str;
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
str += "scanned_pool_txs[" + std::to_string(i) + "]\n";
|
||||
for (auto el : m_scanned_pool_txs[i]) {
|
||||
str += string_tools::pod_to_hex(el) + "\n";
|
||||
}
|
||||
str += "\n";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printTxPrefix(const cryptonote::transaction_prefix &tx)
|
||||
{
|
||||
std::string str;
|
||||
str += "tx.version: " + std::to_string(tx.version) + "\n";
|
||||
str += "tx.unlock_time: " + std::to_string(tx.unlock_time) + "\n";
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printPaymentDetails(const payment_details &pd)
|
||||
{
|
||||
std::string str;
|
||||
str += "tx_hash: " + string_tools::pod_to_hex(pd.m_tx_hash) + "\n";
|
||||
str += "amount: " + std::to_string(pd.m_amount) + "\n";
|
||||
str += "amounts: ";
|
||||
for (auto em : pd.m_amounts) {
|
||||
str += std::to_string(em);
|
||||
}
|
||||
str += "\n";
|
||||
str += "fee: " + std::to_string(pd.m_fee) + "\n";
|
||||
str += "block_height: " + std::to_string(pd.m_block_height) + "\n";
|
||||
str += "unlock_time: " + std::to_string(pd.m_unlock_time) + "\n";
|
||||
str += "timestamp: " + std::to_string(pd.m_timestamp) + "\n";
|
||||
str += "coinbase: " + std::to_string(pd.m_coinbase) + "\n";
|
||||
str += "subaddr_index: " + std::to_string(pd.m_subaddr_index.major) + "," + std::to_string(pd.m_subaddr_index.minor) + "\n";
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string wallet2::printTxDestinationEntry(const cryptonote::tx_destination_entry &tx)
|
||||
{
|
||||
std::string str;
|
||||
str += " original: " + tx.original + "\n";
|
||||
str += " amount: " + std::to_string(tx.amount) + "\n";
|
||||
str += " addr: " + string_tools::pod_to_hex(tx.addr) + "\n";
|
||||
str += " is_subaddress: " + std::to_string(tx.is_subaddress) + "\n";
|
||||
str += " is_integrated: " + std::to_string(tx.is_integrated) + "\n";
|
||||
return str;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists)
|
||||
{
|
||||
|
|
|
@ -232,7 +232,7 @@ private:
|
|||
friend class wallet_keys_unlocker;
|
||||
friend class wallet_device_callback;
|
||||
public:
|
||||
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::chrono::seconds(30);
|
||||
static constexpr const std::chrono::seconds rpc_timeout = std::chrono::seconds(10);
|
||||
|
||||
enum RefreshType {
|
||||
RefreshFull,
|
||||
|
@ -910,6 +910,7 @@ private:
|
|||
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
|
||||
std::string get_address_as_str() const { return get_subaddress_as_str({0, 0}); }
|
||||
std::string get_integrated_address_as_str(const crypto::hash8& payment_id) const;
|
||||
bool get_subaddress_used(const cryptonote::subaddress_index& index);
|
||||
void add_subaddress_account(const std::string& label);
|
||||
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; }
|
||||
|
@ -1388,6 +1389,7 @@ private:
|
|||
bool import_key_images(std::vector<crypto::key_image> key_images, size_t offset=0, boost::optional<std::unordered_set<size_t>> selected_transfers=boost::none);
|
||||
bool import_key_images(signed_tx_set & signed_tx, size_t offset=0, bool only_selected_transfers=false);
|
||||
crypto::public_key get_tx_pub_key_from_received_outs(const tools::wallet2::transfer_details &td) const;
|
||||
void import_tx(const std::string &txid, std::vector<uint64_t> &o_indices, uint64_t height, uint8_t block_version, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen);
|
||||
|
||||
void update_pool_state(std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &process_txs, bool refreshed = false);
|
||||
void process_pool_state(const std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> &txs);
|
||||
|
@ -1532,6 +1534,27 @@ private:
|
|||
uint64_t get_bytes_sent() const;
|
||||
uint64_t get_bytes_received() const;
|
||||
|
||||
std::string printBlockchain();
|
||||
std::string printTransfers();
|
||||
std::string printKeyImages();
|
||||
std::string printUnconfirmedTransferDetails();
|
||||
std::string printPayments();
|
||||
std::string printUnconfirmedPayments();
|
||||
std::string printConfirmedTransferDetails();
|
||||
std::string printPubKeys();
|
||||
std::string printTxNotes();
|
||||
std::string printSubaddresses();
|
||||
std::string printSubaddressLabels();
|
||||
std::string printAdditionalTxKeys();
|
||||
std::string printAttributes();
|
||||
std::string printAccountTags();
|
||||
std::string printTxKeys();
|
||||
std::string printAddressBook();
|
||||
std::string printScannedPoolTxs();
|
||||
std::string printTxPrefix(const cryptonote::transaction_prefix &tx);
|
||||
std::string printPaymentDetails(const payment_details &pd);
|
||||
std::string printTxDestinationEntry(const cryptonote::tx_destination_entry &tx);
|
||||
|
||||
// MMS -------------------------------------------------------------------------------------------------
|
||||
mms::message_store& get_message_store() { return m_message_store; };
|
||||
const mms::message_store& get_message_store() const { return m_message_store; };
|
||||
|
@ -1558,6 +1581,7 @@ 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.
|
||||
|
|
Loading…
Reference in New Issue