Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifications to enable Offline Signing in monero-gui and possible... #9492

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions src/wallet/api/pending_transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,44 @@ bool PendingTransactionImpl::commit(const std::string &filename, bool overwrite)
return m_status == Status_Ok;
}

std::string PendingTransactionImpl::commit_string()
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
{

std::string tx;
LOG_PRINT_L3("m_pending_tx size: " << m_pending_tx.size());

try {
tx = m_wallet.m_wallet->dump_tx_to_str(m_pending_tx);
m_status = Status_Ok;
} catch (const tools::error::daemon_busy&) {
// TODO: make it translatable with "tr"?
m_errorString = tr("daemon is busy. Please try again later.");
m_status = Status_Error;
} catch (const tools::error::no_connection_to_daemon&) {
m_errorString = tr("no connection to daemon. Please make sure daemon is running.");
m_status = Status_Error;
} catch (const tools::error::tx_rejected& e) {
std::ostringstream writer(m_errorString);
writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status();
std::string reason = e.reason();
m_status = Status_Error;
m_errorString = writer.str();
if (!reason.empty())
m_errorString += string(tr(". Reason: ")) + reason;
} catch (const std::exception &e) {
m_errorString = string(tr("Unknown exception: ")) + e.what();
m_status = Status_Error;
} catch (...) {
m_errorString = tr("Unhandled exception");
LOG_ERROR(m_errorString);
m_status = Status_Error;
}
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
m_wallet.startRefresh();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think this is needed.

if (m_status != Status_Ok)
return "";
return tx;
}

uint64_t PendingTransactionImpl::amount() const
{
uint64_t result = 0;
Expand Down
1 change: 1 addition & 0 deletions src/wallet/api/pending_transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ class PendingTransactionImpl : public PendingTransaction
~PendingTransactionImpl();
int status() const override;
std::string errorString() const override;
std::string commit_string() override;
bool commit(const std::string &filename = "", bool overwrite = false) override;
uint64_t amount() const override;
uint64_t dust() const override;
Expand Down
22 changes: 22 additions & 0 deletions src/wallet/api/unsigned_transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,28 @@ bool UnsignedTransactionImpl::sign(const std::string &signedFileName)
return true;
}

std::string UnsignedTransactionImpl::signAsString()
{
if(m_wallet.watchOnly())
{
m_errorString = tr("This is a watch only wallet");
m_status = Status_Error;
return "";
}
tools::wallet2::signed_tx_set signed_txes;
std::vector<tools::wallet2::pending_tx> ptx;
try
{
return m_wallet.m_wallet->sign_tx_dump_to_str(m_unsigned_tx_set, ptx, signed_txes);
}
catch (const std::exception &e)
{
m_errorString = string(tr("Failed to sign transaction")) + e.what();
m_status = Status_Error;
return "";
}
}

//----------------------------------------------------------------------------------------------------
bool UnsignedTransactionImpl::checkLoadedTx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message)
{
Expand Down
1 change: 1 addition & 0 deletions src/wallet/api/unsigned_transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class UnsignedTransactionImpl : public UnsignedTransaction
uint64_t txCount() const override;
// sign txs and save to file
bool sign(const std::string &signedFileName) override;
std::string signAsString() override;
std::string confirmationMessage() const override {return m_confirmationMessage;}
uint64_t minMixinCount() const override;

Expand Down
137 changes: 137 additions & 0 deletions src/wallet/api/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1134,6 +1134,27 @@ UnsignedTransaction *WalletImpl::loadUnsignedTx(const std::string &unsigned_file
return transaction;
}

UnsignedTransaction *WalletImpl::loadUnsignedTxFromString(const std::string &data) {
clearStatus();
UnsignedTransactionImpl * transaction = new UnsignedTransactionImpl(*this);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminds me of this issue: #9461

if (checkBackgroundSync("cannot load tx") || !m_wallet->parse_unsigned_tx_from_str(data, 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 (!std::get<2>(transaction->m_unsigned_tx_set.transfers).empty())
extra_message = (boost::format("%u outputs to import. ") % (unsigned)std::get<2>(transaction->m_unsigned_tx_set.transfers).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;
}

bool WalletImpl::submitTransaction(const string &fileName) {
clearStatus();
if (checkBackgroundSync("cannot submit tx"))
Expand All @@ -1154,6 +1175,48 @@ bool WalletImpl::submitTransaction(const string &fileName) {
return true;
}

bool WalletImpl::submitTransactionFromString(const string &data) {
clearStatus();
if (checkBackgroundSync("cannot submit tx"))
return false;
std::unique_ptr<PendingTransactionImpl> transaction(new PendingTransactionImpl(*this));

bool r = m_wallet->parse_tx_from_str(data, transaction->m_pending_tx, NULL);
if (!r) {
setStatus(Status_Ok, tr("Failed to load transaction from string"));
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

if(!transaction->commit()) {
setStatusError(transaction->m_errorString);
return false;
}

return true;
}

std::string WalletImpl::exportKeyImagesAsString(bool all)
{
if (m_wallet->watch_only())
{
setStatusError(tr("Wallet is view only"));
return "";
}
if (checkBackgroundSync("cannot export key images"))
return "";

try
{
return m_wallet->export_key_images_string(all);
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
}
catch (const std::exception &e)
{
LOG_ERROR("Error exporting key images: " << e.what());
setStatusError(e.what());
return "";
}
}

bool WalletImpl::exportKeyImages(const string &filename, bool all)
{
if (m_wallet->watch_only())
Expand Down Expand Up @@ -1181,6 +1244,31 @@ bool WalletImpl::exportKeyImages(const string &filename, bool all)
return true;
}

bool WalletImpl::importKeyImagesFromString(const std::string &data)
{
if (checkBackgroundSync("cannot import key images"))
return false;
if (!trustedDaemon()) {
setStatusError(tr("Key images can only be imported with a trusted daemon"));
return false;
}
try
{
uint64_t spent = 0, unspent = 0;
uint64_t height = m_wallet->import_key_images_string(data, spent, unspent);
LOG_PRINT_L2("Signed key images imported to height " << height << ", "
<< print_money(spent) << " spent, " << print_money(unspent) << " unspent");
}
catch (const std::exception &e)
{
LOG_ERROR("Error exporting key images: " << e.what());
setStatusError(string(tr("Failed to import key images: ")) + e.what());
return false;
}

return true;
}
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved

bool WalletImpl::importKeyImages(const string &filename)
{
if (checkBackgroundSync("cannot import key images"))
Expand All @@ -1206,6 +1294,29 @@ bool WalletImpl::importKeyImages(const string &filename)
return true;
}

std::string WalletImpl::exportOutputsAsString(bool all)
{
if (checkBackgroundSync("cannot export outputs"))
return "";
if (m_wallet->key_on_device())
{
setStatusError(string(tr("Not supported on HW wallets.")));
return "";
}

try
{
return m_wallet->export_outputs_to_str(all);
}
catch (const std::exception &e)
{
LOG_ERROR("Error exporting outputs: " << e.what());
setStatusError(string(tr("Error exporting outputs: ")) + e.what());
return "";
}
return "";
}

bool WalletImpl::exportOutputs(const string &filename, bool all)
{
if (checkBackgroundSync("cannot export outputs"))
Expand Down Expand Up @@ -1238,6 +1349,32 @@ bool WalletImpl::exportOutputs(const string &filename, bool all)
return true;
}

bool WalletImpl::importOutputsFromString(const std::string &data)
{
if (checkBackgroundSync("cannot import outputs"))
return false;
if (m_wallet->key_on_device())
{
setStatusError(string(tr("Not supported on HW wallets.")));
return false;
}


try
{
size_t n_outputs = m_wallet->import_outputs_from_str(data);
LOG_PRINT_L2(std::to_string(n_outputs) << " outputs imported");
}
catch (const std::exception &e)
{
LOG_ERROR("Failed to import outputs: " << e.what());
setStatusError(string(tr("Failed to import outputs: ")) + e.what());
return false;
}

return true;
}

bool WalletImpl::importOutputs(const string &filename)
{
if (checkBackgroundSync("cannot import outputs"))
Expand Down
6 changes: 6 additions & 0 deletions src/wallet/api/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,16 @@ class WalletImpl : public Wallet
std::set<uint32_t> subaddr_indices = {}) override;
virtual PendingTransaction * createSweepUnmixableTransaction() override;
bool submitTransaction(const std::string &fileName) override;
bool submitTransactionFromString(const std::string &fileName) override;
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override;
virtual UnsignedTransaction * loadUnsignedTxFromString(const std::string &unsigned_filename) override;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keyword virtual should be used in the interface file wallet2_api.h only. (I know this is violated already in several places in the current API.)

And parameter name unsigned_filename should be data.

std::string exportKeyImagesAsString(bool all = false) override;
bool exportKeyImages(const std::string &filename, bool all = false) override;
bool importKeyImagesFromString(const std::string &data) override;
bool importKeyImages(const std::string &filename) override;
std::string exportOutputsAsString(bool all = false) override;
bool exportOutputs(const std::string &filename, bool all = false) override;
bool importOutputsFromString(const std::string &data) override;
bool importOutputs(const std::string &filename) override;
bool scanTransactions(const std::vector<std::string> &txids) override;

Expand Down
49 changes: 48 additions & 1 deletion src/wallet/api/wallet2_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ struct PendingTransaction
virtual ~PendingTransaction() = 0;
virtual int status() const = 0;
virtual std::string errorString() const = 0;
// return string of transaction gives the same content which would be saved to file with commit(filename)
virtual std::string commit_string() = 0;
// commit transaction or save to file if filename is provided.
virtual bool commit(const std::string &filename = "", bool overwrite = false) = 0;
virtual uint64_t amount() const = 0;
Expand Down Expand Up @@ -161,6 +163,11 @@ struct UnsignedTransaction
* return - true on success
*/
virtual bool sign(const std::string &signedFileName) = 0;
/*!
* @brief sign - Sign txs and return as string
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved
* return - true on success
*/
virtual std::string signAsString() = 0;
};

/**
Expand Down Expand Up @@ -895,11 +902,24 @@ struct Wallet
*/
virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) = 0;

/*!
* \brief loadUnsignedTxFromString - creates transaction from unsigned tx string
* \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status()
* after object returned
*/
virtual UnsignedTransaction * loadUnsignedTxFromString(const std::string &unsigned_filename) = 0;
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved

/*!
* \brief submitTransaction - submits transaction in signed tx file
* \return - true on success
*/
virtual bool submitTransaction(const std::string &fileName) = 0;

/*!
* \brief submitTransactionFromString - submits transaction in signed tx file
* \return - true on success
*/
virtual bool submitTransactionFromString(const std::string &fileName) = 0;
DiosDelRayo marked this conversation as resolved.
Show resolved Hide resolved


/*!
Expand All @@ -916,13 +936,27 @@ struct Wallet
virtual uint64_t estimateTransactionFee(const std::vector<std::pair<std::string, uint64_t>> &destinations,
PendingTransaction::Priority priority) const = 0;

/*!
* \brief exportKeyImages - exports key images as string
* \param all - export all key images or only those that have not yet been exported
* \return - key images as std::string
*/
virtual std::string exportKeyImagesAsString(bool all = false) = 0;

/*!
* \brief exportKeyImages - exports key images to file
* \param filename
* \param all - export all key images or only those that have not yet been exported
* \return - true on success
*/
virtual bool exportKeyImages(const std::string &filename, bool all = false) = 0;

/*!
* \brief importKeyImagesFromString - imports key images from string for UR use.
* \param data
* \return - true on success
*/
virtual bool importKeyImagesFromString(const std::string &data) = 0;

/*!
* \brief importKeyImages - imports key images from file
Expand All @@ -932,12 +966,25 @@ struct Wallet
virtual bool importKeyImages(const std::string &filename) = 0;

/*!
* \brief importOutputs - exports outputs to file
* \brief exportOutputsAsString - exports outputs to a string for UR
* \return - true on success
*/
virtual std::string exportOutputsAsString(bool all = false) = 0;

/*!
* \brief exportOutputs - exports outputs to file
* \param filename
* \return - true on success
*/
virtual bool exportOutputs(const std::string &filename, bool all = false) = 0;

/*!
* \brief importOutputsFromString - imports outputs from string for UR
* \param filename
* \return - true on success
*/
virtual bool importOutputsFromString(const std::string &data) = 0;

/*!
* \brief importOutputs - imports outputs from file
* \param filename
Expand Down
Loading
Loading