Merge pull request #2309
d58700e0
WalletAPI: only allow trusted daemon when importing key images (Jaquee)8a9bbd26
WalletAPI: copy wallet data when creating a view only wallet (Jaquee)d27fe32e
wallet2: export/import wallet data functions (Jaquee)225a25f3
import_key_images - allow importing without being connected to daemon (Jaquee)
This commit is contained in:
commit
10da3051c2
|
@ -379,7 +379,32 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
|
||||||
const cryptonote::account_public_address address = m_wallet->get_account().get_keys().m_account_address;
|
const cryptonote::account_public_address address = m_wallet->get_account().get_keys().m_account_address;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Generate view only wallet
|
||||||
view_wallet->generate(path, password, address, viewkey);
|
view_wallet->generate(path, password, address, viewkey);
|
||||||
|
|
||||||
|
// Export/Import outputs
|
||||||
|
auto outputs = m_wallet->export_outputs();
|
||||||
|
view_wallet->import_outputs(outputs);
|
||||||
|
|
||||||
|
// Copy scanned blockchain
|
||||||
|
auto bc = m_wallet->export_blockchain();
|
||||||
|
view_wallet->import_blockchain(bc);
|
||||||
|
|
||||||
|
// copy payments
|
||||||
|
auto payments = m_wallet->export_payments();
|
||||||
|
view_wallet->import_payments(payments);
|
||||||
|
|
||||||
|
// copy confirmed outgoing payments
|
||||||
|
std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> out_payments;
|
||||||
|
m_wallet->get_payments_out(out_payments, 0);
|
||||||
|
view_wallet->import_payments_out(out_payments);
|
||||||
|
|
||||||
|
// Export/Import key images
|
||||||
|
// We already know the spent status from the outputs we exported, thus no need to check them again
|
||||||
|
auto key_images = m_wallet->export_key_images();
|
||||||
|
uint64_t spent = 0;
|
||||||
|
uint64_t unspent = 0;
|
||||||
|
view_wallet->import_key_images(key_images,spent,unspent,false);
|
||||||
m_status = Status_Ok;
|
m_status = Status_Ok;
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
LOG_ERROR("Error creating view only wallet: " << e.what());
|
LOG_ERROR("Error creating view only wallet: " << e.what());
|
||||||
|
@ -387,6 +412,8 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
|
||||||
m_errorString = e.what();
|
m_errorString = e.what();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// Store wallet
|
||||||
|
view_wallet->store();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -862,6 +889,11 @@ bool WalletImpl::exportKeyImages(const string &filename)
|
||||||
|
|
||||||
bool WalletImpl::importKeyImages(const string &filename)
|
bool WalletImpl::importKeyImages(const string &filename)
|
||||||
{
|
{
|
||||||
|
if (!trustedDaemon()) {
|
||||||
|
m_status = Status_Error;
|
||||||
|
m_errorString = tr("Key images can only be imported with a trusted daemon");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
uint64_t spent = 0, unspent = 0;
|
uint64_t spent = 0, unspent = 0;
|
||||||
|
|
|
@ -5330,7 +5330,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent)
|
uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent)
|
||||||
{
|
{
|
||||||
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
|
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
|
||||||
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
|
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
|
||||||
|
@ -5379,6 +5379,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
m_transfers[n].m_key_image_known = true;
|
m_transfers[n].m_key_image_known = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(check_spent)
|
||||||
|
{
|
||||||
m_daemon_rpc_mutex.lock();
|
m_daemon_rpc_mutex.lock();
|
||||||
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
|
bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
|
||||||
m_daemon_rpc_mutex.unlock();
|
m_daemon_rpc_mutex.unlock();
|
||||||
|
@ -5388,25 +5390,77 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
|
THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
|
||||||
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
|
"daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
|
||||||
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
|
std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
|
||||||
|
|
||||||
spent = 0;
|
|
||||||
unspent = 0;
|
|
||||||
for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
|
for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
|
||||||
{
|
{
|
||||||
transfer_details &td = m_transfers[n];
|
transfer_details &td = m_transfers[n];
|
||||||
uint64_t amount = td.amount();
|
|
||||||
td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
|
td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spent = 0;
|
||||||
|
unspent = 0;
|
||||||
|
for(size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
|
{
|
||||||
|
transfer_details &td = m_transfers[i];
|
||||||
|
uint64_t amount = td.amount();
|
||||||
if (td.m_spent)
|
if (td.m_spent)
|
||||||
spent += amount;
|
spent += amount;
|
||||||
else
|
else
|
||||||
unspent += amount;
|
unspent += amount;
|
||||||
LOG_PRINT_L2("Transfer " << n << ": " << print_money(amount) << " (" << td.m_global_output_index << "): "
|
LOG_PRINT_L2("Transfer " << i << ": " << print_money(amount) << " (" << td.m_global_output_index << "): "
|
||||||
<< (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[n] << ")");
|
<< (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")");
|
||||||
}
|
}
|
||||||
LOG_PRINT_L1("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
|
MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
|
||||||
|
|
||||||
return m_transfers[signed_key_images.size() - 1].m_block_height;
|
return m_transfers[signed_key_images.size() - 1].m_block_height;
|
||||||
}
|
}
|
||||||
|
wallet2::payment_container wallet2::export_payments() const
|
||||||
|
{
|
||||||
|
payment_container payments;
|
||||||
|
for (auto const &p : m_payments)
|
||||||
|
{
|
||||||
|
payments.emplace(p);
|
||||||
|
}
|
||||||
|
return payments;
|
||||||
|
}
|
||||||
|
void wallet2::import_payments(const payment_container &payments)
|
||||||
|
{
|
||||||
|
m_payments.clear();
|
||||||
|
for (auto const &p : payments)
|
||||||
|
{
|
||||||
|
m_payments.emplace(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void wallet2::import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments)
|
||||||
|
{
|
||||||
|
m_confirmed_txs.clear();
|
||||||
|
for (auto const &p : confirmed_payments)
|
||||||
|
{
|
||||||
|
m_confirmed_txs.emplace(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<crypto::hash> wallet2::export_blockchain() const
|
||||||
|
{
|
||||||
|
std::vector<crypto::hash> bc;
|
||||||
|
for (auto const &b : m_blockchain)
|
||||||
|
{
|
||||||
|
bc.push_back(b);
|
||||||
|
}
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wallet2::import_blockchain(const std::vector<crypto::hash> &bc)
|
||||||
|
{
|
||||||
|
m_blockchain.clear();
|
||||||
|
for (auto const &b : bc)
|
||||||
|
{
|
||||||
|
m_blockchain.push_back(b);
|
||||||
|
}
|
||||||
|
cryptonote::block genesis;
|
||||||
|
generate_genesis(genesis);
|
||||||
|
crypto::hash genesis_hash = get_block_hash(genesis);
|
||||||
|
check_genesis(genesis_hash);
|
||||||
|
m_local_bc_height = m_blockchain.size();
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
std::vector<tools::wallet2::transfer_details> wallet2::export_outputs() const
|
std::vector<tools::wallet2::transfer_details> wallet2::export_outputs() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -582,12 +582,17 @@ namespace tools
|
||||||
std::string sign(const std::string &data) const;
|
std::string sign(const std::string &data) const;
|
||||||
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
|
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
|
||||||
|
|
||||||
|
// Import/Export wallet data
|
||||||
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
std::vector<tools::wallet2::transfer_details> export_outputs() const;
|
||||||
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
|
||||||
|
payment_container export_payments() const;
|
||||||
|
void import_payments(const payment_container &payments);
|
||||||
|
void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
|
||||||
|
std::vector<crypto::hash> export_blockchain() const;
|
||||||
|
void import_blockchain(const std::vector<crypto::hash> &bc);
|
||||||
bool export_key_images(const std::string filename);
|
bool export_key_images(const std::string filename);
|
||||||
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
|
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
|
||||||
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent);
|
uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
|
||||||
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
|
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
|
||||||
|
|
||||||
void update_pool_state(bool refreshed = false);
|
void update_pool_state(bool refreshed = false);
|
||||||
|
|
Loading…
Reference in New Issue