Merge pull request #1 from monero-project/master
Catch up with Monero master
This commit is contained in:
commit
2d9dfd0820
@ -413,4 +413,13 @@ std::string get_nix_version_display_string()
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void set_strict_default_file_permissions(bool strict)
|
||||
{
|
||||
#if defined(__MINGW32__) || defined(__MINGW__)
|
||||
// no clue about the odd one out
|
||||
#else
|
||||
mode_t mode = strict ? 077 : 0;
|
||||
umask(mode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -158,4 +158,6 @@ namespace tools
|
||||
/*! \brief where the installed handler is stored */
|
||||
static std::function<void(int)> m_handler;
|
||||
};
|
||||
|
||||
void set_strict_default_file_permissions(bool strict);
|
||||
}
|
||||
|
@ -2015,18 +2015,12 @@ bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block
|
||||
TIME_MEASURE_START(a);
|
||||
bool res = check_tx_inputs(tx, tvc, &max_used_block_height);
|
||||
TIME_MEASURE_FINISH(a);
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
if(m_show_time_stats)
|
||||
LOG_PRINT_L0("HASH: " << "+" << " VIN/VOUT: " << tx.vin.size() << "/" << tx.vout.size() << " H: " << max_used_block_height << " chcktx: " << a + m_fake_scan_time);
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
// ND: Speedup:
|
||||
// 1. keep a list of verified transactions, when the Blockchain tries to check a tx again,
|
||||
// verify against list and skip if already verified to be correct.
|
||||
m_check_tx_inputs_table.emplace(tx_prefix_hash, std::make_pair(res, max_used_block_height));
|
||||
|
||||
CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height());
|
||||
max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height);
|
||||
return true;
|
||||
@ -2076,16 +2070,6 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context
|
||||
|
||||
crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx);
|
||||
|
||||
auto its = m_check_tx_inputs_table.find(tx_prefix_hash);
|
||||
if (its != m_check_tx_inputs_table.end())
|
||||
{
|
||||
if (!its->second.first)
|
||||
return false;
|
||||
if (pmax_used_block_height)
|
||||
*pmax_used_block_height = its->second.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
// from hard fork 2, we require mixin at least 2 unless one output cannot mix with 2 others
|
||||
// if one output cannot mix with 2 others, we accept at most 1 output that can mix
|
||||
if (m_hardfork->get_current_version() >= 2)
|
||||
@ -2159,6 +2143,7 @@ bool Blockchain::check_tx_inputs(const transaction& tx, tx_verification_context
|
||||
if(ioservice_active) \
|
||||
{ \
|
||||
work.reset(); \
|
||||
while (!ioservice.stopped()) ioservice.poll(); \
|
||||
threadpool.join_all(); \
|
||||
ioservice.stop(); \
|
||||
ioservice_active = false; \
|
||||
@ -2967,7 +2952,6 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
|
||||
TIME_MEASURE_FINISH(t1);
|
||||
m_blocks_longhash_table.clear();
|
||||
m_scan_table.clear();
|
||||
m_check_tx_inputs_table.clear();
|
||||
m_blocks_txs_check.clear();
|
||||
m_check_txin_table.clear();
|
||||
|
||||
@ -3115,7 +3099,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list<block_complete_e
|
||||
m_fake_pow_calc_time = 0;
|
||||
|
||||
m_scan_table.clear();
|
||||
m_check_tx_inputs_table.clear();
|
||||
m_check_txin_table.clear();
|
||||
|
||||
TIME_MEASURE_FINISH(prepare);
|
||||
|
@ -790,7 +790,6 @@ namespace cryptonote
|
||||
|
||||
// metadata containers
|
||||
std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, std::vector<output_data_t>>> m_scan_table;
|
||||
std::unordered_map<crypto::hash, std::pair<bool, uint64_t>> m_check_tx_inputs_table;
|
||||
std::unordered_map<crypto::hash, crypto::hash> m_blocks_longhash_table;
|
||||
std::unordered_map<crypto::hash, std::unordered_map<crypto::key_image, bool>> m_check_txin_table;
|
||||
|
||||
|
@ -145,7 +145,19 @@ namespace cryptonote
|
||||
[&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); });
|
||||
|
||||
CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero");
|
||||
CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded");
|
||||
if (height == 0)
|
||||
{
|
||||
// the genesis block was not decomposed, for unknown reasons
|
||||
while (max_outs < out_amounts.size())
|
||||
{
|
||||
out_amounts[out_amounts.size() - 2] += out_amounts.back();
|
||||
out_amounts.resize(out_amounts.size() - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(max_outs >= out_amounts.size(), false, "max_out exceeded");
|
||||
}
|
||||
|
||||
uint64_t summary_amounts = 0;
|
||||
for (size_t no = 0; no < out_amounts.size(); no++)
|
||||
|
@ -512,7 +512,7 @@ namespace cryptonote
|
||||
{
|
||||
if(txd.max_used_block_height >= m_blockchain.get_current_blockchain_height())
|
||||
return false;
|
||||
if(m_blockchain.get_block_id_by_height(txd.max_used_block_height) != txd.max_used_block_id)
|
||||
if(true)
|
||||
{
|
||||
//if we already failed on this height and id, skip actual ring signature check
|
||||
if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height))
|
||||
|
@ -70,6 +70,23 @@ namespace {
|
||||
<< "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl
|
||||
<< "reward: " << boost::lexical_cast<std::string>(header.reward);
|
||||
}
|
||||
|
||||
std::string get_human_time_ago(time_t t, time_t now)
|
||||
{
|
||||
if (t == now)
|
||||
return "now";
|
||||
time_t dt = t > now ? t - now : now - t;
|
||||
std::string s;
|
||||
if (dt < 90)
|
||||
s = boost::lexical_cast<std::string>(dt) + " seconds";
|
||||
else if (dt < 90 * 60)
|
||||
s = boost::lexical_cast<std::string>(dt/60) + " minutes";
|
||||
else if (dt < 36 * 3600)
|
||||
s = boost::lexical_cast<std::string>(dt/3600) + " hours";
|
||||
else
|
||||
s = boost::lexical_cast<std::string>(dt/(3600*24)) + " days";
|
||||
return s + " " + (t > now ? "in the future" : "ago");
|
||||
}
|
||||
}
|
||||
|
||||
t_rpc_command_executor::t_rpc_command_executor(
|
||||
@ -575,16 +592,26 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) {
|
||||
}
|
||||
}
|
||||
|
||||
if (1 == res.txs_as_hex.size())
|
||||
if (1 == res.txs.size() || 1 == res.txs_as_hex.size())
|
||||
{
|
||||
if (1 == res.txs.size())
|
||||
{
|
||||
// only available for new style answers
|
||||
if (res.txs.front().in_pool)
|
||||
tools::success_msg_writer() << "Found in pool";
|
||||
else
|
||||
tools::success_msg_writer() << "Found in blockchain at height " << res.txs.front().block_height;
|
||||
}
|
||||
|
||||
// first as hex
|
||||
tools::success_msg_writer() << res.txs_as_hex.front();
|
||||
const std::string &as_hex = (1 == res.txs.size()) ? res.txs.front().as_hex : res.txs_as_hex.front();
|
||||
tools::success_msg_writer() << as_hex;
|
||||
|
||||
// then as json
|
||||
crypto::hash tx_hash, tx_prefix_hash;
|
||||
cryptonote::transaction tx;
|
||||
cryptonote::blobdata blob;
|
||||
if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), blob))
|
||||
if (!string_tools::parse_hexstr_to_binbuff(as_hex, blob))
|
||||
{
|
||||
tools::fail_msg_writer() << "Failed to parse tx";
|
||||
}
|
||||
@ -669,6 +696,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
|
||||
}
|
||||
if (! res.transactions.empty())
|
||||
{
|
||||
const time_t now = time(NULL);
|
||||
tools::msg_writer() << "Transactions: ";
|
||||
for (auto & tx_info : res.transactions)
|
||||
{
|
||||
@ -676,7 +704,7 @@ bool t_rpc_command_executor::print_transaction_pool_long() {
|
||||
<< tx_info.tx_json << std::endl
|
||||
<< "blob_size: " << tx_info.blob_size << std::endl
|
||||
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
|
||||
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
|
||||
@ -747,17 +775,21 @@ bool t_rpc_command_executor::print_transaction_pool_short() {
|
||||
{
|
||||
tools::msg_writer() << "Pool is empty" << std::endl;
|
||||
}
|
||||
for (auto & tx_info : res.transactions)
|
||||
else
|
||||
{
|
||||
tools::msg_writer() << "id: " << tx_info.id_hash << std::endl
|
||||
<< "blob_size: " << tx_info.blob_size << std::endl
|
||||
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << std::endl
|
||||
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
|
||||
<< "last_failed_height: " << tx_info.last_failed_height << std::endl
|
||||
<< "last_failed_id: " << tx_info.last_failed_id_hash << std::endl;
|
||||
const time_t now = time(NULL);
|
||||
for (auto & tx_info : res.transactions)
|
||||
{
|
||||
tools::msg_writer() << "id: " << tx_info.id_hash << std::endl
|
||||
<< "blob_size: " << tx_info.blob_size << std::endl
|
||||
<< "fee: " << cryptonote::print_money(tx_info.fee) << std::endl
|
||||
<< "receive_time: " << tx_info.receive_time << " (" << get_human_time_ago(tx_info.receive_time, now) << ")" << std::endl
|
||||
<< "kept_by_block: " << (tx_info.kept_by_block ? 'T' : 'F') << std::endl
|
||||
<< "max_used_block_height: " << tx_info.max_used_block_height << std::endl
|
||||
<< "max_used_block_id: " << tx_info.max_used_block_id_hash << std::endl
|
||||
<< "last_failed_height: " << tx_info.last_failed_height << std::endl
|
||||
<< "last_failed_id: " << tx_info.last_failed_id_hash << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -240,6 +240,7 @@ namespace cryptonote
|
||||
|
||||
// try the pool for any missing txes
|
||||
size_t found_in_pool = 0;
|
||||
std::unordered_set<crypto::hash> pool_tx_hashes;
|
||||
if (!missed_txs.empty())
|
||||
{
|
||||
std::list<transaction> pool_txs;
|
||||
@ -248,9 +249,11 @@ namespace cryptonote
|
||||
{
|
||||
for (std::list<transaction>::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i)
|
||||
{
|
||||
std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), get_transaction_hash(*i));
|
||||
crypto::hash tx_hash = get_transaction_hash(*i);
|
||||
std::list<crypto::hash>::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), tx_hash);
|
||||
if (mi != missed_txs.end())
|
||||
{
|
||||
pool_tx_hashes.insert(tx_hash);
|
||||
missed_txs.erase(mi);
|
||||
txs.push_back(*i);
|
||||
++found_in_pool;
|
||||
@ -260,12 +263,33 @@ namespace cryptonote
|
||||
LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool");
|
||||
}
|
||||
|
||||
std::list<std::string>::const_iterator txhi = req.txs_hashes.begin();
|
||||
std::vector<crypto::hash>::const_iterator vhi = vh.begin();
|
||||
BOOST_FOREACH(auto& tx, txs)
|
||||
{
|
||||
res.txs.push_back(COMMAND_RPC_GET_TRANSACTIONS::entry());
|
||||
COMMAND_RPC_GET_TRANSACTIONS::entry &e = res.txs.back();
|
||||
|
||||
crypto::hash tx_hash = *vhi++;
|
||||
e.tx_hash = *txhi++;
|
||||
blobdata blob = t_serializable_object_to_blob(tx);
|
||||
res.txs_as_hex.push_back(string_tools::buff_to_hex_nodelimer(blob));
|
||||
e.as_hex = string_tools::buff_to_hex_nodelimer(blob);
|
||||
if (req.decode_as_json)
|
||||
res.txs_as_json.push_back(obj_to_json_str(tx));
|
||||
e.as_json = obj_to_json_str(tx);
|
||||
e.in_pool = pool_tx_hashes.find(tx_hash) != pool_tx_hashes.end();
|
||||
if (e.in_pool)
|
||||
{
|
||||
e.block_height = std::numeric_limits<uint64_t>::max();
|
||||
}
|
||||
else
|
||||
{
|
||||
e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash);
|
||||
}
|
||||
|
||||
// fill up old style responses too, in case an old wallet asks
|
||||
res.txs_as_hex.push_back(e.as_hex);
|
||||
if (req.decode_as_json)
|
||||
res.txs_as_json.push_back(e.as_json);
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const auto& miss_tx, missed_txs)
|
||||
@ -273,7 +297,7 @@ namespace cryptonote
|
||||
res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx));
|
||||
}
|
||||
|
||||
LOG_PRINT_L2(res.txs_as_hex.size() << " transactions found, " << res.missed_tx.size() << " not found");
|
||||
LOG_PRINT_L2(res.txs.size() << " transactions found, " << res.missed_tx.size() << " not found");
|
||||
res.status = CORE_RPC_STATUS_OK;
|
||||
return true;
|
||||
}
|
||||
@ -383,7 +407,7 @@ namespace cryptonote
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!tvc.m_should_be_relayed)
|
||||
if(!tvc.m_should_be_relayed || req.do_not_relay)
|
||||
{
|
||||
LOG_PRINT_L0("[on_send_raw_tx]: tx accepted, but not relayed");
|
||||
res.reason = "Not relayed";
|
||||
|
@ -103,18 +103,41 @@ namespace cryptonote
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct entry
|
||||
{
|
||||
std::string tx_hash;
|
||||
std::string as_hex;
|
||||
std::string as_json;
|
||||
bool in_pool;
|
||||
uint64_t block_height;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_hash)
|
||||
KV_SERIALIZE(as_hex)
|
||||
KV_SERIALIZE(as_json)
|
||||
KV_SERIALIZE(in_pool)
|
||||
KV_SERIALIZE(block_height)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::list<std::string> txs_as_hex; //transactions blobs as hex
|
||||
// older compatibility stuff
|
||||
std::list<std::string> txs_as_hex; //transactions blobs as hex (old compat)
|
||||
std::list<std::string> txs_as_json; //transactions decoded as json (old compat)
|
||||
|
||||
// in both old and new
|
||||
std::list<std::string> missed_tx; //not found transactions
|
||||
std::list<std::string> txs_as_json; //transactions decoded as json
|
||||
|
||||
// new style
|
||||
std::vector<entry> txs;
|
||||
std::string status;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(txs_as_hex)
|
||||
KV_SERIALIZE(missed_tx)
|
||||
KV_SERIALIZE(txs_as_json)
|
||||
KV_SERIALIZE(txs)
|
||||
KV_SERIALIZE(missed_tx)
|
||||
KV_SERIALIZE(status)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
@ -221,12 +244,14 @@ namespace cryptonote
|
||||
struct request
|
||||
{
|
||||
std::string tx_as_hex;
|
||||
bool do_not_relay;
|
||||
|
||||
request() {}
|
||||
explicit request(const transaction &);
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(tx_as_hex)
|
||||
KV_SERIALIZE(do_not_relay)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -829,6 +829,8 @@ static bool get_password(const boost::program_options::variables_map& vm, bool a
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
bool simple_wallet::generate_from_json(const boost::program_options::variables_map& vm, std::string &wallet_file, std::string &password)
|
||||
{
|
||||
bool testnet = command_line::get_arg(vm, arg_testnet);
|
||||
|
||||
std::string buf;
|
||||
bool r = epee::file_io_utils::load_file_to_string(m_generate_from_json, buf);
|
||||
if (!r) {
|
||||
@ -868,6 +870,11 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
return false;
|
||||
}
|
||||
viewkey = *reinterpret_cast<const crypto::secret_key*>(viewkey_data.data());
|
||||
crypto::public_key pkey;
|
||||
if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
|
||||
fail_msg_writer() << tr("failed to verify view key secret key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, spendkey, std::string, String, false);
|
||||
@ -881,6 +888,11 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
return false;
|
||||
}
|
||||
spendkey = *reinterpret_cast<const crypto::secret_key*>(spendkey_data.data());
|
||||
crypto::public_key pkey;
|
||||
if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
|
||||
fail_msg_writer() << tr("failed to verify spend key secret key");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, seed, std::string, String, false);
|
||||
@ -896,6 +908,8 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
m_restore_deterministic_wallet = true;
|
||||
}
|
||||
|
||||
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, address, std::string, String, false);
|
||||
|
||||
// compatibility checks
|
||||
if (!field_seed_found && !field_viewkey_found)
|
||||
{
|
||||
@ -908,6 +922,44 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
return false;
|
||||
}
|
||||
|
||||
// if an address was given, we check keys against it, and deduce the spend
|
||||
// public key if it was not given
|
||||
if (field_address_found)
|
||||
{
|
||||
cryptonote::account_public_address address;
|
||||
bool has_payment_id;
|
||||
crypto::hash8 new_payment_id;
|
||||
if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, field_address))
|
||||
{
|
||||
fail_msg_writer() << tr("invalid address");
|
||||
return false;
|
||||
}
|
||||
if (field_viewkey_found)
|
||||
{
|
||||
crypto::public_key pkey;
|
||||
if (!crypto::secret_key_to_public_key(viewkey, pkey)) {
|
||||
fail_msg_writer() << tr("failed to verify view key secret key");
|
||||
return false;
|
||||
}
|
||||
if (address.m_view_public_key != pkey) {
|
||||
fail_msg_writer() << tr("view key does not match standard address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (field_spendkey_found)
|
||||
{
|
||||
crypto::public_key pkey;
|
||||
if (!crypto::secret_key_to_public_key(spendkey, pkey)) {
|
||||
fail_msg_writer() << tr("failed to verify spend key secret key");
|
||||
return false;
|
||||
}
|
||||
if (address.m_spend_public_key != pkey) {
|
||||
fail_msg_writer() << tr("spend key does not match standard address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_wallet_file = field_filename;
|
||||
|
||||
bool was_deprecated_wallet = m_restore_deterministic_wallet && ((old_language == crypto::ElectrumWords::old_language_name) ||
|
||||
@ -917,7 +969,6 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
return false;
|
||||
}
|
||||
|
||||
bool testnet = command_line::get_arg(vm, arg_testnet);
|
||||
m_wallet.reset(new tools::wallet2(testnet));
|
||||
m_wallet->callback(this);
|
||||
|
||||
@ -934,17 +985,27 @@ bool simple_wallet::generate_from_json(const boost::program_options::variables_m
|
||||
fail_msg_writer() << tr("failed to verify view key secret key");
|
||||
return false;
|
||||
}
|
||||
if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) {
|
||||
fail_msg_writer() << tr("failed to verify spend key secret key");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (field_spendkey.empty())
|
||||
{
|
||||
// if we have an addres but no spend key, we can deduce the spend public key
|
||||
// from the address
|
||||
if (field_address_found)
|
||||
{
|
||||
cryptonote::account_public_address address2;
|
||||
bool has_payment_id;
|
||||
crypto::hash8 new_payment_id;
|
||||
get_account_integrated_address_from_str(address2, has_payment_id, new_payment_id, testnet, field_address);
|
||||
address.m_spend_public_key = address2.m_spend_public_key;
|
||||
}
|
||||
m_wallet->generate(m_wallet_file, password, address, viewkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!crypto::secret_key_to_public_key(spendkey, address.m_spend_public_key)) {
|
||||
fail_msg_writer() << tr("failed to verify spend key secret key");
|
||||
return false;
|
||||
}
|
||||
m_wallet->generate(m_wallet_file, password, address, spendkey, viewkey);
|
||||
}
|
||||
}
|
||||
@ -2133,9 +2194,9 @@ bool simple_wallet::transfer_main(bool new_algorithm, const std::vector<std::str
|
||||
// figure out what tx will be necessary
|
||||
std::vector<tools::wallet2::pending_tx> ptx_vector;
|
||||
if (new_algorithm)
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra);
|
||||
ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon);
|
||||
else
|
||||
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra);
|
||||
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra, m_trusted_daemon);
|
||||
|
||||
// if more than one tx necessary, prompt user to confirm
|
||||
if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1)
|
||||
@ -2497,13 +2558,18 @@ bool simple_wallet::check_tx_key(const std::vector<std::string> &args_)
|
||||
COMMAND_RPC_GET_TRANSACTIONS::response res;
|
||||
req.txs_hashes.push_back(epee::string_tools::pod_to_hex(txid));
|
||||
if (!net_utils::invoke_http_json_remote_command2(m_daemon_address + "/gettransactions", req, res, m_http_client) ||
|
||||
res.txs_as_hex.empty())
|
||||
(res.txs.empty() && res.txs_as_hex.empty()))
|
||||
{
|
||||
fail_msg_writer() << tr("failed to get transaction from daemon");
|
||||
return true;
|
||||
}
|
||||
cryptonote::blobdata tx_data;
|
||||
if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data))
|
||||
bool ok;
|
||||
if (!res.txs.empty())
|
||||
ok = string_tools::parse_hexstr_to_binbuff(res.txs.front().as_hex, tx_data);
|
||||
else
|
||||
ok = string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), tx_data);
|
||||
if (!ok)
|
||||
{
|
||||
fail_msg_writer() << tr("failed to parse transaction from daemon");
|
||||
return true;
|
||||
@ -2807,6 +2873,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
std::string lang = i18n_get_language();
|
||||
tools::sanitize_locale();
|
||||
tools::set_strict_default_file_permissions(true);
|
||||
|
||||
string_tools::set_module_name_and_folder(argv[0]);
|
||||
|
||||
@ -2963,12 +3030,25 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
|
||||
tools::wallet2 wal(testnet,restricted);
|
||||
bool quit = false;
|
||||
tools::signal_handler::install([&wal, &quit](int) {
|
||||
quit = true;
|
||||
wal.stop();
|
||||
});
|
||||
try
|
||||
{
|
||||
LOG_PRINT_L0(sw::tr("Loading wallet..."));
|
||||
wal.load(wallet_file, password);
|
||||
wal.init(daemon_address);
|
||||
wal.refresh();
|
||||
// if we ^C during potentially length load/refresh, there's no server loop yet
|
||||
if (quit)
|
||||
{
|
||||
LOG_PRINT_L0(sw::tr("Storing wallet..."));
|
||||
wal.store();
|
||||
LOG_PRINT_GREEN(sw::tr("Stored ok"), LOG_LEVEL_0);
|
||||
return 1;
|
||||
}
|
||||
LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -2979,10 +3059,8 @@ int main(int argc, char* argv[])
|
||||
tools::wallet_rpc_server wrpc(wal);
|
||||
bool r = wrpc.init(vm);
|
||||
CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet rpc server"));
|
||||
|
||||
tools::signal_handler::install([&wrpc, &wal](int) {
|
||||
wrpc.send_stop_signal();
|
||||
wal.store();
|
||||
});
|
||||
LOG_PRINT_L0(sw::tr("Starting wallet rpc server"));
|
||||
wrpc.run();
|
||||
|
@ -73,6 +73,7 @@ using namespace cryptonote;
|
||||
#define KILL_IOSERVICE() \
|
||||
do { \
|
||||
work.reset(); \
|
||||
while (!ioservice.stopped()) ioservice.poll(); \
|
||||
threadpool.join_all(); \
|
||||
ioservice.stop(); \
|
||||
} while(0)
|
||||
@ -1749,47 +1750,12 @@ namespace
|
||||
// returns:
|
||||
// direct return: amount of money found
|
||||
// modified reference: selected_transfers, a list of iterators/indices of input sources
|
||||
uint64_t wallet2::select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, bool hf2_rules, std::list<transfer_container::iterator>& selected_transfers)
|
||||
uint64_t wallet2::select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::list<transfer_container::iterator>& selected_transfers, bool trusted_daemon)
|
||||
{
|
||||
std::vector<size_t> unused_transfers_indices;
|
||||
std::vector<size_t> unused_dust_indices;
|
||||
|
||||
// aggregate sources available for transfers
|
||||
// if dust needed, take dust from only one source (so require source has at least dust amount)
|
||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||
{
|
||||
const transfer_details& td = m_transfers[i];
|
||||
if (!td.m_spent && is_transfer_unlocked(td))
|
||||
{
|
||||
if (dust < td.amount() && is_valid_decomposed_amount(td.amount()))
|
||||
unused_transfers_indices.push_back(i);
|
||||
else
|
||||
{
|
||||
// for hf2 rules, we disregard dust, which will be spendable only
|
||||
// via sweep_dust. If we're asked to add dust, though, we still
|
||||
// consider them, as this will be a mixin 0 tx (and thus we may
|
||||
// end up with a tx with one mixable output and N dusty ones).
|
||||
// This should be made better at some point...
|
||||
if (!hf2_rules || add_dust)
|
||||
unused_dust_indices.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool select_one_dust = add_dust && !unused_dust_indices.empty();
|
||||
uint64_t found_money = 0;
|
||||
while (found_money < needed_money && (!unused_transfers_indices.empty() || !unused_dust_indices.empty()))
|
||||
while (found_money < needed_money && !unused_transfers_indices.empty())
|
||||
{
|
||||
size_t idx;
|
||||
if (select_one_dust)
|
||||
{
|
||||
idx = pop_random_value(unused_dust_indices);
|
||||
select_one_dust = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices);
|
||||
}
|
||||
size_t idx = pop_random_value(unused_transfers_indices);
|
||||
|
||||
transfer_container::iterator it = m_transfers.begin() + idx;
|
||||
selected_transfers.push_back(it);
|
||||
@ -1811,18 +1777,18 @@ void wallet2::add_unconfirmed_tx(const cryptonote::transaction& tx, const std::v
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
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, pending_tx& ptx)
|
||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon)
|
||||
{
|
||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx);
|
||||
transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), tx, ptx, trusted_daemon);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
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)
|
||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, bool trusted_daemon)
|
||||
{
|
||||
cryptonote::transaction tx;
|
||||
pending_tx ptx;
|
||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, tx, ptx);
|
||||
transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, tx, ptx, trusted_daemon);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1974,6 +1940,7 @@ void wallet2::commit_tx(pending_tx& ptx)
|
||||
|
||||
COMMAND_RPC_SEND_RAW_TX::request req;
|
||||
req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx));
|
||||
req.do_not_relay = false;
|
||||
COMMAND_RPC_SEND_RAW_TX::response daemon_send_resp;
|
||||
m_daemon_rpc_mutex.lock();
|
||||
bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/sendrawtransaction", req, daemon_send_resp, m_http_client, 200000);
|
||||
@ -2019,8 +1986,9 @@ void wallet2::commit_tx(std::vector<pending_tx>& ptx_vector)
|
||||
//
|
||||
// this function will make multiple calls to wallet2::transfer if multiple
|
||||
// transactions will be required
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra)
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon)
|
||||
{
|
||||
const std::vector<size_t> unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, trusted_daemon);
|
||||
|
||||
// failsafe split attempt counter
|
||||
size_t attempt_count = 0;
|
||||
@ -2050,7 +2018,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions(std::vector<crypto
|
||||
uint64_t needed_fee = 0;
|
||||
do
|
||||
{
|
||||
transfer(dst_vector, fake_outs_count, unlock_time, needed_fee, extra, tx, ptx);
|
||||
transfer(dst_vector, fake_outs_count, unused_transfers_indices, unlock_time, needed_fee, extra, tx, ptx, trusted_daemon);
|
||||
auto txBlob = t_serializable_object_to_blob(ptx.tx);
|
||||
needed_fee = calculate_fee(txBlob);
|
||||
} while (ptx.fee < needed_fee);
|
||||
@ -2283,7 +2251,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
|
||||
// This system allows for sending (almost) the entire balance, since it does
|
||||
// not generate spurious change in all txes, thus decreasing the instantaneous
|
||||
// usable balance.
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra)
|
||||
std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon)
|
||||
{
|
||||
std::vector<size_t> unused_transfers_indices;
|
||||
std::vector<size_t> unused_dust_indices;
|
||||
@ -2703,9 +2671,8 @@ std::vector<uint64_t> wallet2::get_unspent_amounts_vector()
|
||||
return vector;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_daemon)
|
||||
std::vector<size_t> wallet2::select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon)
|
||||
{
|
||||
// request all outputs with at least 3 instances, so we can use mixin 2 with
|
||||
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request> req_t = AUTO_VAL_INIT(req_t);
|
||||
epee::json_rpc::response<cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response, std::string> resp_t = AUTO_VAL_INIT(resp_t);
|
||||
m_daemon_rpc_mutex.lock();
|
||||
@ -2714,7 +2681,7 @@ std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_dae
|
||||
req_t.method = "get_output_histogram";
|
||||
if (trusted_daemon)
|
||||
req_t.params.amounts = get_unspent_amounts_vector();
|
||||
req_t.params.min_count = 3;
|
||||
req_t.params.min_count = count;
|
||||
req_t.params.max_count = 0;
|
||||
bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client);
|
||||
m_daemon_rpc_mutex.unlock();
|
||||
@ -2728,14 +2695,32 @@ std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_dae
|
||||
mixable.insert(i.amount);
|
||||
}
|
||||
|
||||
return select_available_outputs([mixable](const transfer_details &td) {
|
||||
return select_available_outputs([mixable, atleast](const transfer_details &td) {
|
||||
const uint64_t amount = td.amount();
|
||||
if (mixable.find(amount) == mixable.end())
|
||||
return true;
|
||||
if (atleast) {
|
||||
if (mixable.find(amount) != mixable.end())
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (mixable.find(amount) == mixable.end())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> wallet2::select_available_unmixable_outputs(bool trusted_daemon)
|
||||
{
|
||||
// request all outputs with less than 3 instances
|
||||
return select_available_outputs_from_histogram(3, false, trusted_daemon);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<size_t> wallet2::select_available_mixable_outputs(bool trusted_daemon)
|
||||
{
|
||||
// request all outputs with at least 3 instances, so we can use mixin 2 with
|
||||
return select_available_outputs_from_histogram(3, true, trusted_daemon);
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions(bool trusted_daemon)
|
||||
{
|
||||
// From hard fork 1, we don't consider small amounts to be dust anymore
|
||||
|
@ -274,11 +274,11 @@ namespace tools
|
||||
uint64_t unlocked_balance() const;
|
||||
uint64_t unlocked_dust_balance(const tx_dust_policy &dust_policy) const;
|
||||
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, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon);
|
||||
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, 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, cryptonote::transaction& tx, pending_tx& ptx);
|
||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, 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, bool trusted_daemon);
|
||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, bool trusted_daemon);
|
||||
void transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices, uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx& ptx, bool trusted_daemon);
|
||||
template<typename T>
|
||||
void transfer_from(const std::vector<size_t> &outs, size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx);
|
||||
template<typename T>
|
||||
@ -287,8 +287,8 @@ namespace tools
|
||||
|
||||
void commit_tx(pending_tx& ptx_vector);
|
||||
void commit_tx(std::vector<pending_tx>& ptx_vector);
|
||||
std::vector<pending_tx> 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);
|
||||
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra);
|
||||
std::vector<pending_tx> 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 trusted_daemon);
|
||||
std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector<uint8_t> extra, bool trusted_daemon);
|
||||
std::vector<pending_tx> create_unmixable_sweep_transactions(bool trusted_daemon);
|
||||
bool check_connection();
|
||||
void get_transfers(wallet2::transfer_container& incoming_transfers) const;
|
||||
@ -389,7 +389,7 @@ namespace tools
|
||||
void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::list<cryptonote::block_complete_entry> &blocks);
|
||||
void pull_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::list<cryptonote::block_complete_entry> &prev_blocks, std::list<cryptonote::block_complete_entry> &blocks, bool &error);
|
||||
void process_blocks(uint64_t start_height, const std::list<cryptonote::block_complete_entry> &blocks, uint64_t& blocks_added);
|
||||
uint64_t select_transfers(uint64_t needed_money, bool add_dust, uint64_t dust, bool hf2_rules, std::list<transfer_container::iterator>& selected_transfers);
|
||||
uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::list<transfer_container::iterator>& selected_transfers, bool trusted_daemon);
|
||||
bool prepare_file_names(const std::string& file_path);
|
||||
void process_unconfirmed(const cryptonote::transaction& tx, uint64_t height);
|
||||
void process_outgoing(const cryptonote::transaction& tx, uint64_t height, uint64_t spent, uint64_t received);
|
||||
@ -403,8 +403,10 @@ namespace tools
|
||||
uint64_t get_upper_tranaction_size_limit();
|
||||
void check_pending_txes();
|
||||
std::vector<uint64_t> get_unspent_amounts_vector();
|
||||
std::vector<size_t> select_available_outputs_from_histogram(uint64_t count, bool atleast, bool trusted_daemon);
|
||||
std::vector<size_t> select_available_outputs(const std::function<bool(const transfer_details &td)> &f);
|
||||
std::vector<size_t> select_available_unmixable_outputs(bool trusted_daemon);
|
||||
std::vector<size_t> select_available_mixable_outputs(bool trusted_daemon);
|
||||
|
||||
cryptonote::account_base m_account;
|
||||
std::string m_daemon_address;
|
||||
@ -562,17 +564,17 @@ namespace tools
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
template<typename T>
|
||||
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)
|
||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, const size_t fake_outs_count, const std::vector<size_t> &unused_transfers_indices,
|
||||
uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, bool trusted_daemon)
|
||||
{
|
||||
pending_tx ptx;
|
||||
cryptonote::transaction tx;
|
||||
transfer(dsts, fake_outputs_count, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx);
|
||||
transfer(dsts, fake_outs_count, unused_transfers_indices, unlock_time, fee, extra, destination_split_strategy, dust_policy, tx, ptx, trusted_daemon);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
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, pending_tx &ptx)
|
||||
void wallet2::transfer(const std::vector<cryptonote::tx_destination_entry>& dsts, size_t fake_outputs_count, const std::vector<size_t> &unused_transfers_indices,
|
||||
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, bool trusted_daemon)
|
||||
{
|
||||
using namespace cryptonote;
|
||||
// throw if attempting a transaction with no destinations
|
||||
@ -593,9 +595,7 @@ namespace tools
|
||||
// randomly select inputs for transaction
|
||||
// throw if requested send amount is greater than amount available to send
|
||||
std::list<transfer_container::iterator> selected_transfers;
|
||||
bool hf2_rules = use_fork_rules(2); // first fork has version 2
|
||||
const bool add_dust = (0 == fake_outputs_count) && hf2_rules;
|
||||
uint64_t found_money = select_transfers(needed_money, add_dust, dust_policy.dust_threshold, hf2_rules, selected_transfers);
|
||||
uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon);
|
||||
THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_money, found_money, needed_money - fee, fee);
|
||||
|
||||
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
|
||||
|
@ -232,7 +232,7 @@ namespace tools
|
||||
LOG_PRINT_L1("Requested mixin " << req.mixin << " too low for hard fork 2, using 2");
|
||||
mixin = 2;
|
||||
}
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra);
|
||||
std::vector<wallet2::pending_tx> ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
||||
|
||||
// reject proposed transactions if there are more than one. see on_transfer_split below.
|
||||
if (ptx_vector.size() != 1)
|
||||
@ -299,9 +299,9 @@ namespace tools
|
||||
}
|
||||
std::vector<wallet2::pending_tx> ptx_vector;
|
||||
if (req.new_algorithm)
|
||||
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee, extra);
|
||||
ptx_vector = m_wallet.create_transactions_2(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
||||
else
|
||||
ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra);
|
||||
ptx_vector = m_wallet.create_transactions(dsts, mixin, req.unlock_time, req.fee, extra, req.trusted_daemon);
|
||||
|
||||
m_wallet.commit_tx(ptx_vector);
|
||||
|
||||
|
@ -115,6 +115,7 @@ namespace wallet_rpc
|
||||
uint64_t unlock_time;
|
||||
std::string payment_id;
|
||||
bool get_tx_key;
|
||||
bool trusted_daemon;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(destinations)
|
||||
@ -123,6 +124,7 @@ namespace wallet_rpc
|
||||
KV_SERIALIZE(unlock_time)
|
||||
KV_SERIALIZE(payment_id)
|
||||
KV_SERIALIZE(get_tx_key)
|
||||
KV_SERIALIZE(trusted_daemon)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
@ -149,6 +151,7 @@ namespace wallet_rpc
|
||||
std::string payment_id;
|
||||
bool new_algorithm;
|
||||
bool get_tx_keys;
|
||||
bool trusted_daemon;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(destinations)
|
||||
@ -158,6 +161,7 @@ namespace wallet_rpc
|
||||
KV_SERIALIZE(payment_id)
|
||||
KV_SERIALIZE(new_algorithm)
|
||||
KV_SERIALIZE(get_tx_keys)
|
||||
KV_SERIALIZE(trusted_daemon)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
@ -470,13 +470,15 @@ inline bool replay_events_through_core(cryptonote::core& cr, const std::vector<t
|
||||
CATCH_ENTRY_L0("replay_events_through_core", false);
|
||||
}
|
||||
//--------------------------------------------------------------------------
|
||||
template<class t_test_class>
|
||||
template<typename t_test_class>
|
||||
struct get_test_options {
|
||||
const std::pair<uint8_t, uint64_t> hard_forks[1] = {std::make_pair((uint8_t)1, (uint64_t)0)};
|
||||
const std::pair<uint8_t, uint64_t> hard_forks[1];
|
||||
const cryptonote::test_options test_options = {
|
||||
hard_forks
|
||||
};
|
||||
get_test_options():hard_forks{std::make_pair((uint8_t)1, (uint64_t)0)}{}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
template<class t_test_class>
|
||||
inline bool do_replay_events(std::vector<test_event_entry>& events)
|
||||
|
@ -85,7 +85,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor,
|
||||
try
|
||||
{
|
||||
tools::wallet2::pending_tx ptx;
|
||||
w1.transfer(dsts, mix_in_factor, 0, TEST_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx);
|
||||
w1.transfer(dsts, mix_in_factor, 0, TEST_FEE, std::vector<uint8_t>(), tools::detail::null_split_strategy, tools::tx_dust_policy(TEST_DUST_THRESHOLD), tx, ptx, true);
|
||||
w1.commit_tx(ptx);
|
||||
return true;
|
||||
}
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#ifdef STATICLIB
|
||||
|
||||
extern "C" int dnskey_algo_id_is_supported(int);
|
||||
|
||||
TEST(unbound, supported_algorithms)
|
||||
@ -47,3 +49,5 @@ TEST(unbound, supported_algorithms)
|
||||
ASSERT_TRUE(dnskey_algo_id_is_supported(13));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user