Merge pull request #3780

9c2a7b4 wallet-rpc: watch-only and cold wallet features added (ph4r05)
This commit is contained in:
luigi1111 2018-06-16 14:12:57 -05:00
commit 4e7897e57c
No known key found for this signature in database
GPG key ID: F4ACA0183641E010
7 changed files with 495 additions and 98 deletions

View file

@ -712,7 +712,7 @@ namespace tools
//------------------------------------------------------------------------------------------------------------------------------
template<typename Ts, typename Tu>
bool wallet_rpc_server::fill_response(std::vector<tools::wallet2::pending_tx> &ptx_vector,
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, bool do_not_relay,
bool get_tx_key, Ts& tx_key, Tu &amount, Tu &fee, std::string &multisig_txset, std::string &unsigned_txset, bool do_not_relay,
Ts &tx_hash, bool get_tx_hex, Ts &tx_blob, bool get_tx_metadata, Ts &tx_metadata, epee::json_rpc::error &er)
{
for (const auto & ptx : ptx_vector)
@ -741,7 +741,16 @@ namespace tools
}
else
{
if (!do_not_relay)
if (m_wallet->watch_only()){
unsigned_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->dump_tx_to_str(ptx_vector));
if (unsigned_txset.empty())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "Failed to save unsigned tx set after creation";
return false;
}
}
else if (!do_not_relay)
m_wallet->commit_tx(ptx_vector);
// populate response with tx hashes
@ -811,7 +820,7 @@ namespace tools
return false;
}
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
@ -858,7 +867,7 @@ namespace tools
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
@ -869,6 +878,141 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sign_transfer(const wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SIGN_TRANSFER::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
if (m_wallet->key_on_device())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "command not supported by HW wallet";
return false;
}
if(m_wallet->watch_only())
{
er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY;
er.message = "command not supported by watch-only wallet";
return false;
}
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.unsigned_txset, blob))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
er.message = "Failed to parse hex.";
return false;
}
tools::wallet2::unsigned_tx_set exported_txs;
if(!m_wallet->parse_unsigned_tx_from_str(blob, exported_txs))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_UNSIGNED_TX_DATA;
er.message = "cannot load unsigned_txset";
return false;
}
std::vector<tools::wallet2::pending_tx> ptxs;
try
{
tools::wallet2::signed_tx_set signed_txs;
std::string ciphertext = m_wallet->sign_tx_dump_to_str(exported_txs, ptxs, signed_txs);
if (ciphertext.empty())
{
er.code = WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED;
er.message = "Failed to sign unsigned tx";
return false;
}
res.signed_txset = epee::string_tools::buff_to_hex_nodelimer(ciphertext);
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_SIGN_UNSIGNED;
er.message = std::string("Failed to sign unsigned tx: ") + e.what();
return false;
}
for (auto &ptx: ptxs)
{
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
}
if (req.export_raw)
{
for (auto &ptx: ptxs)
{
res.tx_raw_list.push_back(epee::string_tools::buff_to_hex_nodelimer(cryptonote::tx_to_blob(ptx.tx)));
}
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_submit_transfer(const wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_TRANSFER::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
if (m_wallet->key_on_device())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "command not supported by HW wallet";
return false;
}
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
er.message = "Failed to parse hex.";
return false;
}
std::vector<tools::wallet2::pending_tx> ptx_vector;
try
{
bool r = m_wallet->parse_tx_from_str(blob, ptx_vector, NULL);
if (!r)
{
er.code = WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA;
er.message = "Failed to parse signed tx data.";
return false;
}
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_BAD_SIGNED_TX_DATA;
er.message = std::string("Failed to parse signed tx: ") + e.what();
return false;
}
try
{
for (auto &ptx: ptx_vector)
{
m_wallet->commit_tx(ptx);
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
}
}
catch (const std::exception &e)
{
er.code = WALLET_RPC_ERROR_CODE_SIGNED_SUBMISSION;
er.message = std::string("Failed to submit signed tx: ") + e.what();
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_sweep_dust(const wallet_rpc::COMMAND_RPC_SWEEP_DUST::request& req, wallet_rpc::COMMAND_RPC_SWEEP_DUST::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
@ -883,7 +1027,7 @@ namespace tools
{
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
@ -931,7 +1075,7 @@ namespace tools
uint32_t priority = m_wallet->adjust_priority(req.priority);
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.fee_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, er);
}
catch (const std::exception& e)
@ -1007,7 +1151,7 @@ namespace tools
return false;
}
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, req.do_not_relay,
return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.amount, res.fee, res.multisig_txset, res.unsigned_txset, req.do_not_relay,
res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, res.tx_metadata, er);
}
catch (const std::exception& e)
@ -1974,6 +2118,72 @@ namespace tools
return false;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_export_outputs(const wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_EXPORT_OUTPUTS::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
if (m_wallet->key_on_device())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "command not supported by HW wallet";
return false;
}
try
{
res.outputs_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->export_outputs_to_str());
}
catch (const std::exception &e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_import_outputs(const wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::request& req, wallet_rpc::COMMAND_RPC_IMPORT_OUTPUTS::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
if (m_wallet->restricted())
{
er.code = WALLET_RPC_ERROR_CODE_DENIED;
er.message = "Command unavailable in restricted mode.";
return false;
}
if (m_wallet->key_on_device())
{
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
er.message = "command not supported by HW wallet";
return false;
}
cryptonote::blobdata blob;
if (!epee::string_tools::parse_hexstr_to_binbuff(req.outputs_data_hex, blob))
{
er.code = WALLET_RPC_ERROR_CODE_BAD_HEX;
er.message = "Failed to parse hex.";
return false;
}
try
{
res.num_imported = m_wallet->import_outputs_from_str(blob);
}
catch (const std::exception &e)
{
handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR);
return false;
}
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_export_key_images(const wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::request& req, wallet_rpc::COMMAND_RPC_EXPORT_KEY_IMAGES::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);