|
|
@ -610,11 +610,6 @@ namespace tools
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hash
|
|
|
|
|
|
|
|
res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx));
|
|
|
|
|
|
|
|
if (req.get_tx_key)
|
|
|
|
if (req.get_tx_key)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key);
|
|
|
|
res.tx_key = epee::string_tools::pod_to_hex(ptx_vector.back().tx_key);
|
|
|
@ -623,6 +618,23 @@ namespace tools
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res.fee = ptx_vector.back().fee;
|
|
|
|
res.fee = ptx_vector.back().fee;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_wallet->multisig())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
|
|
|
|
|
|
|
|
if (res.multisig_txset.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hash
|
|
|
|
|
|
|
|
res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx_vector.back().tx));
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cryptonote::blobdata blob;
|
|
|
|
cryptonote::blobdata blob;
|
|
|
@ -632,10 +644,20 @@ namespace tools
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::ostringstream oss;
|
|
|
|
binary_archive<true> ar(oss);
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
::serialization::serialize(ar, ptx_vector.back());
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx_vector.back();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
|
|
|
|
res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
catch (const std::exception& e)
|
|
|
@ -675,17 +697,9 @@ namespace tools
|
|
|
|
ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
|
|
|
ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
|
|
|
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
|
|
|
|
LOG_PRINT_L2("on_transfer_split called create_transactions_2");
|
|
|
|
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
LOG_PRINT_L2("on_transfer_split calling commit_tx");
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
LOG_PRINT_L2("on_transfer_split called commit_tx");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
// populate response with tx hashes
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
@ -699,6 +713,33 @@ namespace tools
|
|
|
|
res.amount_list.push_back(ptx_amount);
|
|
|
|
res.amount_list.push_back(ptx_amount);
|
|
|
|
|
|
|
|
|
|
|
|
res.fee_list.push_back(ptx.fee);
|
|
|
|
res.fee_list.push_back(ptx.fee);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_wallet->multisig())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
|
|
|
|
|
|
|
|
if (res.multisig_txset.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
LOG_PRINT_L2("on_transfer_split calling commit_tx");
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
LOG_PRINT_L2("on_transfer_split called commit_tx");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (auto & ptx : ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
|
|
|
|
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -709,11 +750,21 @@ namespace tools
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::ostringstream oss;
|
|
|
|
binary_archive<true> ar(oss);
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
::serialization::serialize(ar, const_cast<tools::wallet2::pending_tx&>(ptx));
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -739,18 +790,43 @@ namespace tools
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
|
|
|
|
std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_unmixable_sweep_transactions(m_trusted_daemon);
|
|
|
|
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
res.fee_list.push_back(ptx.fee);
|
|
|
|
res.fee_list.push_back(ptx.fee);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_wallet->multisig())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (tools::wallet2::pending_tx &ptx: ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (auto & ptx : ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cryptonote::blobdata blob;
|
|
|
|
cryptonote::blobdata blob;
|
|
|
@ -760,11 +836,21 @@ namespace tools
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::ostringstream oss;
|
|
|
|
binary_archive<true> ar(oss);
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
::serialization::serialize(ar, const_cast<tools::wallet2::pending_tx&>(ptx));
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -804,17 +890,42 @@ namespace tools
|
|
|
|
uint64_t mixin = m_wallet->adjust_mixin(req.mixin);
|
|
|
|
uint64_t mixin = m_wallet->adjust_mixin(req.mixin);
|
|
|
|
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, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
|
|
|
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, req.priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon);
|
|
|
|
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
for (const auto & ptx : ptx_vector)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
if (req.get_tx_keys)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
|
res.tx_key_list.push_back(epee::string_tools::pod_to_hex(ptx.tx_key));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_wallet->multisig())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (tools::wallet2::pending_tx &ptx: ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
res.multisig_txset.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
|
|
|
|
for (auto & ptx : ptx_vector)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx)));
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cryptonote::blobdata blob;
|
|
|
|
cryptonote::blobdata blob;
|
|
|
@ -824,11 +935,21 @@ namespace tools
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::ostringstream oss;
|
|
|
|
binary_archive<true> ar(oss);
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
::serialization::serialize(ar, const_cast<tools::wallet2::pending_tx&>(ptx));
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
res.tx_metadata_list.push_back(epee::string_tools::buff_to_hex_nodelimer(oss.str()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -888,23 +1009,36 @@ namespace tools
|
|
|
|
er.message = "Multiple transactions are created, which is not supposed to happen";
|
|
|
|
er.message = "Multiple transactions are created, which is not supposed to happen";
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ptx_vector[0].selected_transfers.size() > 1)
|
|
|
|
const wallet2::pending_tx &ptx = ptx_vector[0];
|
|
|
|
|
|
|
|
if (ptx.selected_transfers.size() > 1)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
er.message = "The transaction uses multiple inputs, which is not supposed to happen";
|
|
|
|
er.message = "The transaction uses multiple inputs, which is not supposed to happen";
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (req.get_tx_key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.tx_key = epee::string_tools::pod_to_hex(ptx.tx_key);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (m_wallet->multisig())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector));
|
|
|
|
|
|
|
|
if (res.multisig_txset.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
if (!req.do_not_relay)
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
m_wallet->commit_tx(ptx_vector);
|
|
|
|
|
|
|
|
|
|
|
|
// populate response with tx hashes
|
|
|
|
// populate response with tx hashes
|
|
|
|
const wallet2::pending_tx &ptx = ptx_vector[0];
|
|
|
|
|
|
|
|
res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx));
|
|
|
|
res.tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx));
|
|
|
|
if (req.get_tx_key)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
res.tx_key = epee::string_tools::pod_to_hex(ptx.tx_key);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
if (req.get_tx_hex)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
cryptonote::blobdata blob;
|
|
|
|
cryptonote::blobdata blob;
|
|
|
@ -914,11 +1048,20 @@ namespace tools
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
if (req.get_tx_metadata)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
std::ostringstream oss;
|
|
|
|
std::ostringstream oss;
|
|
|
|
binary_archive<true> ar(oss);
|
|
|
|
boost::archive::portable_binary_oarchive ar(oss);
|
|
|
|
::serialization::serialize(ar, const_cast<tools::wallet2::pending_tx&>(ptx));
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
ar << ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR;
|
|
|
|
|
|
|
|
er.message = "Failed to save multisig tx set after creation";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
|
|
|
|
res.tx_metadata = epee::string_tools::buff_to_hex_nodelimer(oss.str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const tools::error::daemon_busy& e)
|
|
|
|
catch (const tools::error::daemon_busy& e)
|
|
|
@ -954,13 +1097,14 @@ namespace tools
|
|
|
|
return false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
|
|
ss << blob;
|
|
|
|
|
|
|
|
binary_archive<false> ba(ss);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools::wallet2::pending_tx ptx;
|
|
|
|
tools::wallet2::pending_tx ptx;
|
|
|
|
bool r = ::serialization::serialize(ba, ptx);
|
|
|
|
try
|
|
|
|
if (!r)
|
|
|
|
{
|
|
|
|
|
|
|
|
std::istringstream iss(blob);
|
|
|
|
|
|
|
|
boost::archive::portable_binary_iarchive ar(iss);
|
|
|
|
|
|
|
|
ar >> ptx;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_BAD_TX_METADATA;
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_BAD_TX_METADATA;
|
|
|
|
er.message = "Failed to parse tx metadata.";
|
|
|
|
er.message = "Failed to parse tx metadata.";
|
|
|
@ -2663,6 +2807,141 @@ namespace tools
|
|
|
|
return true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
bool wallet_rpc_server::on_sign_multisig(const wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ready;
|
|
|
|
|
|
|
|
uint32_t threshold, total;
|
|
|
|
|
|
|
|
if (!m_wallet->multisig(&ready, &threshold, &total))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG;
|
|
|
|
|
|
|
|
er.message = "This wallet is not multisig";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ready)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG;
|
|
|
|
|
|
|
|
er.message = "This wallet is multisig, but not yet finalized";
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools::wallet2::multisig_tx_set txs;
|
|
|
|
|
|
|
|
bool r = m_wallet->load_multisig_tx(blob, txs, NULL);
|
|
|
|
|
|
|
|
if (!r)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA;
|
|
|
|
|
|
|
|
er.message = "Failed to parse multisig tx data.";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<crypto::hash> txids;
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
bool r = m_wallet->sign_multisig_tx(txs, txids);
|
|
|
|
|
|
|
|
if (!r)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE;
|
|
|
|
|
|
|
|
er.message = "Failed to sign multisig tx";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (const std::exception &e)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE;
|
|
|
|
|
|
|
|
er.message = std::string("Failed to sign multisig tx: ") + e.what();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
res.tx_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(txs));
|
|
|
|
|
|
|
|
if (!txids.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (const crypto::hash &txid: txids)
|
|
|
|
|
|
|
|
res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(txid));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
bool wallet_rpc_server::on_submit_multisig(const wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ready;
|
|
|
|
|
|
|
|
uint32_t threshold, total;
|
|
|
|
|
|
|
|
if (!m_wallet->multisig(&ready, &threshold, &total))
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG;
|
|
|
|
|
|
|
|
er.message = "This wallet is not multisig";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ready)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG;
|
|
|
|
|
|
|
|
er.message = "This wallet is multisig, but not yet finalized";
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tools::wallet2::multisig_tx_set txs;
|
|
|
|
|
|
|
|
bool r = m_wallet->load_multisig_tx(blob, txs, NULL);
|
|
|
|
|
|
|
|
if (!r)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA;
|
|
|
|
|
|
|
|
er.message = "Failed to parse multisig tx data.";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (txs.m_signers.size() < threshold)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED;
|
|
|
|
|
|
|
|
er.message = "Not enough signers signed this transaction.";
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for (auto &ptx: txs.m_ptx)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
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_MULTISIG_SUBMISSION;
|
|
|
|
|
|
|
|
er.message = std::string("Failed to submit multisig tx: ") + e.what();
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|