final changes to get transaction splitting building. needs testing.
This commit is contained in:
parent
79e59d155b
commit
2e048a4679
|
@ -790,10 +790,10 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
|
||||||
//
|
//
|
||||||
// split amount for each dst in dsts into num_splits parts
|
// split amount for each dst in dsts into num_splits parts
|
||||||
// and make num_splits new vector<crypt...> instances to hold these new amounts
|
// and make num_splits new vector<crypt...> instances to hold these new amounts
|
||||||
vector<vector<cryptonote::tx_destination_entry>> simple_wallet::split_amounts(
|
std::vector<std::vector<cryptonote::tx_destination_entry>> simple_wallet::split_amounts(
|
||||||
vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
|
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits)
|
||||||
{
|
{
|
||||||
vector<vector<cryptonote::tx_destination_entry>> retVal;
|
std::vector<std::vector<cryptonote::tx_destination_entry>> retVal;
|
||||||
|
|
||||||
if (num_splits <= 1)
|
if (num_splits <= 1)
|
||||||
{
|
{
|
||||||
|
@ -804,7 +804,7 @@ vector<vector<cryptonote::tx_destination_entry>> simple_wallet::split_amounts(
|
||||||
// for each split required
|
// for each split required
|
||||||
for (size_t i=0; i < num_splits; i++)
|
for (size_t i=0; i < num_splits; i++)
|
||||||
{
|
{
|
||||||
vector<cryptonote::tx_destination_entry> new_dsts;
|
std::vector<cryptonote::tx_destination_entry> new_dsts;
|
||||||
|
|
||||||
// for each destination
|
// for each destination
|
||||||
for (size_t j=0; j < dsts.size(); j++)
|
for (size_t j=0; j < dsts.size(); j++)
|
||||||
|
@ -836,33 +836,94 @@ vector<vector<cryptonote::tx_destination_entry>> simple_wallet::split_amounts(
|
||||||
//
|
//
|
||||||
// this function will make multiple calls to wallet2::transfer if multiple
|
// this function will make multiple calls to wallet2::transfer if multiple
|
||||||
// transactions will be required
|
// transactions will be required
|
||||||
void simple_wallet::create_transactions(vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra)
|
void simple_wallet::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra)
|
||||||
{
|
{
|
||||||
|
// for now, limit to 5 attempts. TODO: discuss a good number to limit to.
|
||||||
|
const size_t MAX_ATTEMPTS = 5;
|
||||||
|
|
||||||
// failsafe split attempt counter
|
// failsafe split attempt counter
|
||||||
size_t attempt_count = 0;
|
size_t attempt_count = 0;
|
||||||
|
|
||||||
for(attempt_count = 1;;attempt_count++)
|
for(attempt_count = 1; attempt_count <= 5 ;attempt_count++)
|
||||||
{
|
{
|
||||||
|
auto split_values = split_amounts(dsts, attempt_count);
|
||||||
|
|
||||||
|
// Throw if split_amounts comes back with a vector of size different than it should
|
||||||
|
if (split_values.size() != attempt_count)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Splitting transactions returned a number of potential tx not equal to what was requested");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
vector<cryptonote::transaction> tx_vector;
|
|
||||||
for (size_t i=0; i < attempt_count; i++)
|
for (size_t i=0; i < attempt_count; i++)
|
||||||
{
|
{
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
m_wallet->transfer(dsts, fake_outs_count, 0, DEFAULT_FEE, extra, tx);
|
tools::wallet2::pending_tx ptx;
|
||||||
tx_vector.push_back(tx);
|
m_wallet->transfer(dsts, fake_outs_count, unlock_time, fee, extra, tx, ptx);
|
||||||
|
ptx_vector.push_back(ptx);
|
||||||
|
|
||||||
|
// mark transfers to be used as "spent"
|
||||||
|
BOOST_FOREACH(tools::wallet2::transfer_container::iterator it, ptx.selected_transfers)
|
||||||
|
it->m_spent = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we made it this far, we've selected our transactions. committing them will mark them spent,
|
||||||
|
// so this is a failsafe in case they don't go through
|
||||||
|
// unmark pending tx transfers as spent
|
||||||
|
for (auto & ptx : ptx_vector)
|
||||||
|
{
|
||||||
|
// mark transfers to be used as not spent
|
||||||
|
BOOST_FOREACH(tools::wallet2::transfer_container::iterator it2, ptx.selected_transfers)
|
||||||
|
it2->m_spent = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// if we made it this far, we're OK to actually send the transactions
|
// if we made it this far, we're OK to actually send the transactions
|
||||||
|
while (!ptx_vector.empty())
|
||||||
|
{
|
||||||
|
m_wallet->commit_tx(ptx_vector.back());
|
||||||
|
// if no exception, remove element from vector
|
||||||
|
ptx_vector.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
|
|
||||||
// only catch this here, other exceptions need to pass through to the calling function
|
// only catch this here, other exceptions need to pass through to the calling function
|
||||||
catch (const tools::error::tx_too_big& e)
|
catch (const tools::error::tx_too_big& e)
|
||||||
{
|
{
|
||||||
cryptonote::transaction tx = e.tx();
|
|
||||||
fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " is too big. Transaction size: " <<
|
// unmark pending tx transfers as spent
|
||||||
get_object_blobsize(e.tx()) << " bytes, transaction size limit: " << e.tx_size_limit() << " bytes";
|
for (auto & ptx : ptx_vector)
|
||||||
|
{
|
||||||
|
// mark transfers to be used as not spent
|
||||||
|
BOOST_FOREACH(tools::wallet2::transfer_container::iterator it2, ptx.selected_transfers)
|
||||||
|
it2->m_spent = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempt_count >= MAX_ATTEMPTS)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
// in case of some other exception, make sure any tx in queue are marked unspent again
|
||||||
|
|
||||||
|
// unmark pending tx transfers as spent
|
||||||
|
for (auto & ptx : ptx_vector)
|
||||||
|
{
|
||||||
|
// mark transfers to be used as not spent
|
||||||
|
BOOST_FOREACH(tools::wallet2::transfer_container::iterator it2, ptx.selected_transfers)
|
||||||
|
it2->m_spent = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
@ -931,6 +992,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, DEFAULT_FEE, extra);
|
||||||
}
|
}
|
||||||
catch (const tools::error::daemon_busy&)
|
catch (const tools::error::daemon_busy&)
|
||||||
{
|
{
|
||||||
|
@ -980,6 +1042,10 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_)
|
||||||
{
|
{
|
||||||
fail_msg_writer() << "one of destinations is zero";
|
fail_msg_writer() << "one of destinations is zero";
|
||||||
}
|
}
|
||||||
|
catch (const tools::error::tx_too_big& e)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << "Failed to find a suitable way to split transactions";
|
||||||
|
}
|
||||||
catch (const tools::error::transfer_error& e)
|
catch (const tools::error::transfer_error& e)
|
||||||
{
|
{
|
||||||
LOG_ERROR("unknown transfer error: " << e.to_string());
|
LOG_ERROR("unknown transfer error: " << e.to_string());
|
||||||
|
|
|
@ -54,10 +54,10 @@ namespace cryptonote
|
||||||
bool show_payments(const std::vector<std::string> &args);
|
bool show_payments(const std::vector<std::string> &args);
|
||||||
bool show_blockchain_height(const std::vector<std::string> &args);
|
bool show_blockchain_height(const std::vector<std::string> &args);
|
||||||
bool transfer(const std::vector<std::string> &args);
|
bool transfer(const std::vector<std::string> &args);
|
||||||
vector<vector<cryptonote::tx_destination_entry>> simple_wallet::split_amounts(
|
std::vector<std::vector<cryptonote::tx_destination_entry>> split_amounts(
|
||||||
vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
|
std::vector<cryptonote::tx_destination_entry> dsts, size_t num_splits
|
||||||
);
|
);
|
||||||
void create_transactions(vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra);
|
void create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector<uint8_t> extra);
|
||||||
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
|
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
bool save(const std::vector<std::string> &args);
|
bool save(const std::vector<std::string> &args);
|
||||||
bool set_log(const std::vector<std::string> &args);
|
bool set_log(const std::vector<std::string> &args);
|
||||||
|
|
|
@ -685,16 +685,43 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, uint64_t cha
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx)
|
||||||
{
|
{
|
||||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(fee), tx);
|
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(fee), tx, ptx);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra)
|
||||||
{
|
{
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx);
|
pending_tx ptx;
|
||||||
|
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx, ptx);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
// take a pending tx and actually send it to the daemon
|
||||||
|
void wallet2::commit_tx(pending_tx& ptx)
|
||||||
|
{
|
||||||
|
using namespace cryptonote;
|
||||||
|
COMMAND_RPC_SEND_RAW_TX::request req;
|
||||||
|
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
|
||||||
|
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
|
||||||
|
bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
|
||||||
|
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
|
||||||
|
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
|
||||||
|
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, ptx.tx, daemon_send_resp.status);
|
||||||
|
|
||||||
|
add_unconfirmed_tx(ptx.tx, ptx.change_dts.amount);
|
||||||
|
|
||||||
|
LOG_PRINT_L2("transaction " << get_transaction_hash(ptx.tx) << " generated ok and sent to daemon, key_images: [" << ptx.key_images << "]");
|
||||||
|
|
||||||
|
BOOST_FOREACH(transfer_container::iterator it, ptx.selected_transfers)
|
||||||
|
it->m_spent = true;
|
||||||
|
|
||||||
|
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(ptx.tx) << ">" << ENDL
|
||||||
|
<< "Commission: " << print_money(ptx.fee+ptx.dust) << " (dust: " << print_money(ptx.dust) << ")" << ENDL
|
||||||
|
<< "Balance: " << print_money(balance()) << ENDL
|
||||||
|
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
|
||||||
|
<< "Please, wait for confirmation for your balance to be unlocked.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,15 @@ namespace tools
|
||||||
typedef std::vector<transfer_details> transfer_container;
|
typedef std::vector<transfer_details> transfer_container;
|
||||||
typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
|
typedef std::unordered_multimap<crypto::hash, payment_details> payment_container;
|
||||||
|
|
||||||
|
struct pending_tx
|
||||||
|
{
|
||||||
|
cryptonote::transaction tx;
|
||||||
|
uint64_t dust, fee;
|
||||||
|
cryptonote::tx_destination_entry change_dts;
|
||||||
|
std::list<transfer_container::iterator> selected_transfers;
|
||||||
|
std::string key_images;
|
||||||
|
};
|
||||||
|
|
||||||
struct keys_file_data
|
struct keys_file_data
|
||||||
{
|
{
|
||||||
crypto::chacha8_iv iv;
|
crypto::chacha8_iv iv;
|
||||||
|
@ -125,9 +134,10 @@ namespace tools
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy);
|
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx);
|
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx& ptx);
|
||||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra);
|
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra);
|
||||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx);
|
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx);
|
||||||
|
void commit_tx(pending_tx& ptx);
|
||||||
bool check_connection();
|
bool check_connection();
|
||||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||||
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments) const;
|
void get_payments(const crypto::hash& payment_id, std::list<wallet2::payment_details>& payments) const;
|
||||||
|
@ -295,13 +305,14 @@ namespace tools
|
||||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy)
|
||||||
{
|
{
|
||||||
|
pending_tx ptx;
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx);
|
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count,
|
||||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction &tx)
|
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx)
|
||||||
{
|
{
|
||||||
using namespace cryptonote;
|
using namespace cryptonote;
|
||||||
// throw if attempting a transaction with no destinations
|
// throw if attempting a transaction with no destinations
|
||||||
|
@ -432,25 +443,14 @@ namespace tools
|
||||||
});
|
});
|
||||||
THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
|
THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx);
|
||||||
|
|
||||||
COMMAND_RPC_SEND_RAW_TX::request req;
|
ptx.key_images = key_images;
|
||||||
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(tx));
|
ptx.fee = fee;
|
||||||
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
|
ptx.dust = dust;
|
||||||
r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
|
ptx.tx = tx;
|
||||||
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "sendrawtransaction");
|
ptx.change_dts = change_dts;
|
||||||
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "sendrawtransaction");
|
ptx.selected_transfers = selected_transfers;
|
||||||
THROW_WALLET_EXCEPTION_IF(daemon_send_resp.status != CORE_RPC_STATUS_OK, error::tx_rejected, tx, daemon_send_resp.status);
|
|
||||||
|
|
||||||
add_unconfirmed_tx(tx, change_dts.amount);
|
|
||||||
|
|
||||||
LOG_PRINT_L2("transaction " << get_transaction_hash(tx) << " generated ok and sent to daemon, key_images: [" << key_images << "]");
|
|
||||||
|
|
||||||
BOOST_FOREACH(transfer_container::iterator it, selected_transfers)
|
|
||||||
it->m_spent = true;
|
|
||||||
|
|
||||||
LOG_PRINT_L0("Transaction successfully sent. <" << get_transaction_hash(tx) << ">" << ENDL
|
|
||||||
<< "Commission: " << print_money(fee+dust) << " (dust: " << print_money(dust) << ")" << ENDL
|
|
||||||
<< "Balance: " << print_money(balance()) << ENDL
|
|
||||||
<< "Unlocked: " << print_money(unlocked_balance()) << ENDL
|
|
||||||
<< "Please, wait for confirmation for your balance to be unlocked.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,8 @@ namespace tools
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cryptonote::transaction tx;
|
cryptonote::transaction tx;
|
||||||
m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, extra, tx);
|
wallet2::pending_tx ptx;
|
||||||
|
m_wallet.transfer(dsts, req.mixin, req.unlock_time, req.fee, extra, tx, ptx);
|
||||||
res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
|
res.tx_hash = boost::lexical_cast<std::string>(cryptonote::get_transaction_hash(tx));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,9 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx);
|
tools::wallet2::pending_tx ptx;
|
||||||
|
w1.transfer(dsts, mix_in_factor, 0, DEFAULT_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(DEFAULT_FEE), tx, ptx);
|
||||||
|
w1.commit_tx(ptx);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const std::exception&)
|
catch (const std::exception&)
|
||||||
|
|
Loading…
Reference in New Issue