aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blockchain_db/blockchain_db.cpp24
-rw-r--r--src/blockchain_db/blockchain_db.h11
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.cpp31
-rw-r--r--src/blockchain_db/lmdb/db_lmdb.h3
-rw-r--r--src/blockchain_utilities/blockchain_import.cpp6
-rw-r--r--src/common/command_line.cpp17
-rw-r--r--src/common/command_line.h3
-rw-r--r--src/cryptonote_core/blockchain.cpp17
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp23
-rw-r--r--src/cryptonote_core/tx_pool.cpp3
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl41
-rw-r--r--src/daemon/command_server.cpp2
-rw-r--r--src/daemon/main.cpp2
-rw-r--r--src/debug_utilities/CMakeLists.txt1
-rw-r--r--src/p2p/net_peerlist_boost_serialization.h2
-rw-r--r--src/simplewallet/simplewallet.cpp70
-rw-r--r--src/simplewallet/simplewallet.h1
-rw-r--r--src/wallet/api/wallet.cpp32
-rw-r--r--src/wallet/wallet2.cpp148
-rw-r--r--src/wallet/wallet2.h16
20 files changed, 357 insertions, 96 deletions
diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp
index 01a59e079..d62a250ff 100644
--- a/src/blockchain_db/blockchain_db.cpp
+++ b/src/blockchain_db/blockchain_db.cpp
@@ -78,6 +78,23 @@ std::string blockchain_db_types(const std::string& sep)
return ret;
}
+std::string arg_db_type_description = "Specify database type, available: " + cryptonote::blockchain_db_types(", ");
+const command_line::arg_descriptor<std::string> arg_db_type = {
+ "db-type"
+, arg_db_type_description.c_str()
+, DEFAULT_DB_TYPE
+};
+const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
+ "db-sync-mode"
+, "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[nblocks_per_sync]."
+, "fast:async:1000"
+};
+const command_line::arg_descriptor<bool> arg_db_salvage = {
+ "db-salvage"
+, "Try to salvage a blockchain database if it seems corrupted"
+, false
+};
+
BlockchainDB *new_db(const std::string& db_type)
{
if (db_type == "lmdb")
@@ -89,6 +106,13 @@ BlockchainDB *new_db(const std::string& db_type)
return NULL;
}
+void BlockchainDB::init_options(boost::program_options::options_description& desc)
+{
+ command_line::add_arg(desc, arg_db_type);
+ command_line::add_arg(desc, arg_db_sync_mode);
+ command_line::add_arg(desc, arg_db_salvage);
+}
+
void BlockchainDB::pop_block()
{
block blk;
diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h
index ad246d85e..85a494ce7 100644
--- a/src/blockchain_db/blockchain_db.h
+++ b/src/blockchain_db/blockchain_db.h
@@ -33,6 +33,8 @@
#include <list>
#include <string>
#include <exception>
+#include <boost/program_options.hpp>
+#include "common/command_line.h"
#include "crypto/hash.h"
#include "cryptonote_protocol/blobdatatype.h"
#include "cryptonote_basic/cryptonote_basic.h"
@@ -101,6 +103,10 @@ namespace cryptonote
/** a pair of <transaction hash, output index>, typedef for convenience */
typedef std::pair<crypto::hash, uint64_t> tx_out_index;
+extern const command_line::arg_descriptor<std::string> arg_db_type;
+extern const command_line::arg_descriptor<std::string> arg_db_sync_mode;
+extern const command_line::arg_descriptor<bool, false> arg_db_salvage;
+
#pragma pack(push, 1)
/**
@@ -536,6 +542,11 @@ public:
virtual ~BlockchainDB() { };
/**
+ * @brief init command line options
+ */
+ static void init_options(boost::program_options::options_description& desc);
+
+ /**
* @brief reset profiling stats
*/
void reset_stats();
diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp
index 4100d9cca..b6978bdc4 100644
--- a/src/blockchain_db/lmdb/db_lmdb.cpp
+++ b/src/blockchain_db/lmdb/db_lmdb.cpp
@@ -2604,6 +2604,16 @@ void BlockchainLMDB::batch_commit()
memset(&m_wcursors, 0, sizeof(m_wcursors));
}
+void BlockchainLMDB::cleanup_batch()
+{
+ // for destruction of batch transaction
+ m_write_txn = nullptr;
+ delete m_write_batch_txn;
+ m_write_batch_txn = nullptr;
+ m_batch_active = false;
+ memset(&m_wcursors, 0, sizeof(m_wcursors));
+}
+
void BlockchainLMDB::batch_stop()
{
LOG_PRINT_L3("BlockchainLMDB::" << __func__);
@@ -2618,15 +2628,18 @@ void BlockchainLMDB::batch_stop()
check_open();
LOG_PRINT_L3("batch transaction: committing...");
TIME_MEASURE_START(time1);
- m_write_txn->commit();
- TIME_MEASURE_FINISH(time1);
- time_commit1 += time1;
- // for destruction of batch transaction
- m_write_txn = nullptr;
- delete m_write_batch_txn;
- m_write_batch_txn = nullptr;
- m_batch_active = false;
- memset(&m_wcursors, 0, sizeof(m_wcursors));
+ try
+ {
+ m_write_txn->commit();
+ TIME_MEASURE_FINISH(time1);
+ time_commit1 += time1;
+ cleanup_batch();
+ }
+ catch (const std::exception &e)
+ {
+ cleanup_batch();
+ throw;
+ }
LOG_PRINT_L3("batch transaction: end");
}
diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h
index 3a11ddf0d..90274b904 100644
--- a/src/blockchain_db/lmdb/db_lmdb.h
+++ b/src/blockchain_db/lmdb/db_lmdb.h
@@ -368,6 +368,9 @@ private:
// migrate from DB version 0 to 1
void migrate_0_1();
+ void cleanup_batch();
+
+private:
MDB_env* m_env;
MDB_dbi m_blocks;
diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp
index 4a180430f..635a70b10 100644
--- a/src/blockchain_utilities/blockchain_import.cpp
+++ b/src/blockchain_utilities/blockchain_import.cpp
@@ -208,7 +208,8 @@ int check_flush(cryptonote::core &core, std::list<block_complete_entry> &blocks,
}
} // each download block
- core.cleanup_handle_incoming_blocks();
+ if (!core.cleanup_handle_incoming_blocks())
+ return 1;
blocks.clear();
return 0;
@@ -404,7 +405,10 @@ int import_from_file(cryptonote::core& core, const std::string& import_file_path
blocks.push_back({block, txs});
int ret = check_flush(core, blocks, false);
if (ret)
+ {
+ quit = 2; // make sure we don't commit partial block data
break;
+ }
}
else
{
diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp
index ad66b2009..8c03bed0d 100644
--- a/src/common/command_line.cpp
+++ b/src/common/command_line.cpp
@@ -32,7 +32,6 @@
#include <boost/algorithm/string/compare.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <unordered_set>
-#include "blockchain_db/db_types.h"
#include "common/i18n.h"
#include "cryptonote_config.h"
#include "string_tools.h"
@@ -96,22 +95,6 @@ namespace command_line
, "checkpoints from DNS server will be enforced"
, false
};
- std::string arg_db_type_description = "Specify database type, available: " + cryptonote::blockchain_db_types(", ");
- const command_line::arg_descriptor<std::string> arg_db_type = {
- "db-type"
- , arg_db_type_description.c_str()
- , DEFAULT_DB_TYPE
- };
- const command_line::arg_descriptor<std::string> arg_db_sync_mode = {
- "db-sync-mode"
- , "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[nblocks_per_sync]."
- , "fast:async:1000"
- };
- const arg_descriptor<bool> arg_db_salvage = {
- "db-salvage"
- , "Try to salvage a blockchain database if it seems corrupted"
- , false
- };
const command_line::arg_descriptor<uint64_t> arg_fast_block_sync = {
"fast-block-sync"
, "Sync up most of the way by using embedded, known block hashes."
diff --git a/src/common/command_line.h b/src/common/command_line.h
index 03ba35a5b..ac64f519c 100644
--- a/src/common/command_line.h
+++ b/src/common/command_line.h
@@ -212,9 +212,6 @@ namespace command_line
extern const arg_descriptor<int> arg_test_dbg_lock_sleep;
extern const arg_descriptor<bool, false> arg_testnet_on;
extern const arg_descriptor<bool> arg_dns_checkpoints;
- extern const arg_descriptor<std::string> arg_db_type;
- extern const arg_descriptor<std::string> arg_db_sync_mode;
- extern const arg_descriptor<bool, false> arg_db_salvage;
extern const arg_descriptor<uint64_t> arg_fast_block_sync;
extern const arg_descriptor<uint64_t> arg_prep_blocks_threads;
extern const arg_descriptor<uint64_t> arg_show_time_stats;
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index c1faa703f..93a4e26f8 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -3582,12 +3582,23 @@ void Blockchain::block_longhash_worker(uint64_t height, const std::vector<block>
//------------------------------------------------------------------
bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
{
+ bool success = false;
+
MTRACE("Blockchain::" << __func__);
CRITICAL_REGION_BEGIN(m_blockchain_lock);
TIME_MEASURE_START(t1);
- m_db->batch_stop();
- if (m_sync_counter > 0)
+ try
+ {
+ m_db->batch_stop();
+ success = true;
+ }
+ catch (const std::exception &e)
+ {
+ MERROR("Exception in cleanup_handle_incoming_blocks: " << e.what());
+ }
+
+ if (success && m_sync_counter > 0)
{
if (force_sync)
{
@@ -3622,7 +3633,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync)
CRITICAL_REGION_END();
m_tx_pool.unlock();
- return true;
+ return success;
}
//------------------------------------------------------------------
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index c406dd0b4..73ce88c79 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -156,11 +156,8 @@ namespace cryptonote
command_line::add_arg(desc, command_line::arg_testnet_on);
command_line::add_arg(desc, command_line::arg_dns_checkpoints);
- command_line::add_arg(desc, command_line::arg_db_type);
command_line::add_arg(desc, command_line::arg_prep_blocks_threads);
command_line::add_arg(desc, command_line::arg_fast_block_sync);
- command_line::add_arg(desc, command_line::arg_db_sync_mode);
- command_line::add_arg(desc, command_line::arg_db_salvage);
command_line::add_arg(desc, command_line::arg_show_time_stats);
command_line::add_arg(desc, command_line::arg_block_sync_size);
command_line::add_arg(desc, command_line::arg_check_updates);
@@ -170,6 +167,7 @@ namespace cryptonote
command_line::add_arg(desc, nodetool::arg_p2p_bind_port, false);
miner::init_options(desc);
+ BlockchainDB::init_options(desc);
}
//-----------------------------------------------------------------------------------------------
bool core::handle_command_line(const boost::program_options::variables_map& vm)
@@ -279,9 +277,9 @@ namespace cryptonote
m_config_folder_mempool = m_config_folder_mempool + "/" + m_port;
}
- std::string db_type = command_line::get_arg(vm, command_line::arg_db_type);
- std::string db_sync_mode = command_line::get_arg(vm, command_line::arg_db_sync_mode);
- bool db_salvage = command_line::get_arg(vm, command_line::arg_db_salvage) != 0;
+ std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type);
+ std::string db_sync_mode = command_line::get_arg(vm, cryptonote::arg_db_sync_mode);
+ bool db_salvage = command_line::get_arg(vm, cryptonote::arg_db_salvage) != 0;
bool fast_sync = command_line::get_arg(vm, command_line::arg_fast_block_sync) != 0;
uint64_t blocks_threads = command_line::get_arg(vm, command_line::arg_prep_blocks_threads);
std::string check_updates_string = command_line::get_arg(vm, command_line::arg_check_updates);
@@ -585,6 +583,8 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::handle_incoming_txs(const std::list<blobdata>& tx_blobs, std::vector<tx_verification_context>& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
{
+ TRY_ENTRY();
+
struct result { bool res; cryptonote::transaction tx; crypto::hash hash; crypto::hash prefix_hash; bool in_txpool; bool in_blockchain; };
std::vector<result> results(tx_blobs.size());
@@ -638,6 +638,8 @@ namespace cryptonote
MDEBUG("tx added: " << results[i].hash);
}
return ok;
+
+ CATCH_ENTRY_L0("core::handle_incoming_txs()", false);
}
//-----------------------------------------------------------------------------------------------
bool core::handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay)
@@ -1064,17 +1066,20 @@ namespace cryptonote
//-----------------------------------------------------------------------------------------------
bool core::cleanup_handle_incoming_blocks(bool force_sync)
{
+ bool success = false;
try {
- m_blockchain_storage.cleanup_handle_incoming_blocks(force_sync);
+ success = m_blockchain_storage.cleanup_handle_incoming_blocks(force_sync);
}
catch (...) {}
m_incoming_tx_lock.unlock();
- return true;
+ return success;
}
//-----------------------------------------------------------------------------------------------
bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate)
{
+ TRY_ENTRY();
+
// load json & DNS checkpoints every 10min/hour respectively,
// and verify them with respect to what blocks we already have
CHECK_AND_ASSERT_MES(update_checkpoints(), false, "One or more checkpoints loaded from json or dns conflicted with existing checkpoints.");
@@ -1098,6 +1103,8 @@ namespace cryptonote
if(update_miner_blocktemplate && bvc.m_added_to_main_chain)
update_miner_block_template();
return true;
+
+ CATCH_ENTRY_L0("core::handle_incoming_block()", false);
}
//-----------------------------------------------------------------------------------------------
// Used by the RPC server to check the size of an incoming
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 265a4ca3e..68e0b556f 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -863,6 +863,9 @@ namespace cryptonote
std::unordered_set<crypto::key_image> k_images;
LOG_PRINT_L2("Filling block template, median size " << median_size << ", " << m_txs_by_fee_and_receive_time.size() << " txes in the pool");
+
+ LockedTXN lock(m_blockchain);
+
auto sorted_it = m_txs_by_fee_and_receive_time.begin();
while (sorted_it != m_txs_by_fee_and_receive_time.end())
{
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index e762cf9c8..7d95f134b 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -364,7 +364,12 @@ namespace cryptonote
block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
- m_core.cleanup_handle_incoming_blocks(true);
+ if (!m_core.cleanup_handle_incoming_blocks(true))
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ m_core.resume_mine();
+ return 1;
+ }
m_core.resume_mine();
if(bvc.m_verifivation_failed)
{
@@ -623,7 +628,12 @@ namespace cryptonote
block_verification_context bvc = boost::value_initialized<block_verification_context>();
m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block
- m_core.cleanup_handle_incoming_blocks(true);
+ if (!m_core.cleanup_handle_incoming_blocks(true))
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ m_core.resume_mine();
+ return 1;
+ }
m_core.resume_mine();
if( bvc.m_verifivation_failed )
@@ -930,6 +940,7 @@ namespace cryptonote
{
const uint64_t subchain_height = start_height + arg.blocks.size();
LOG_DEBUG_CC(context, "These are old blocks, ignoring: blocks " << start_height << " - " << (subchain_height-1) << ", blockchain height " << m_core.get_current_blockchain_height());
+ m_block_queue.remove_spans(context.m_connection_id, start_height);
goto skip;
}
@@ -1055,7 +1066,11 @@ skip:
}))
LOG_ERROR_CCONTEXT("span connection id not found");
- m_core.cleanup_handle_incoming_blocks();
+ if (!m_core.cleanup_handle_incoming_blocks())
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ return 1;
+ }
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height);
return 1;
@@ -1080,7 +1095,12 @@ skip:
}))
LOG_ERROR_CCONTEXT("span connection id not found");
- m_core.cleanup_handle_incoming_blocks();
+ if (!m_core.cleanup_handle_incoming_blocks())
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ return 1;
+ }
+
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height);
return 1;
@@ -1094,7 +1114,12 @@ skip:
}))
LOG_ERROR_CCONTEXT("span connection id not found");
- m_core.cleanup_handle_incoming_blocks();
+ if (!m_core.cleanup_handle_incoming_blocks())
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ return 1;
+ }
+
// in case the peer had dropped beforehand, remove the span anyway so other threads can wake up and get it
m_block_queue.remove_spans(span_connection_id, start_height);
return 1;
@@ -1107,7 +1132,11 @@ skip:
MCINFO("sync-info", "Block process time (" << blocks.size() << " blocks, " << num_txs << " txs): " << block_process_time_full + transactions_process_time_full << " (" << transactions_process_time_full << "/" << block_process_time_full << ") ms");
- m_core.cleanup_handle_incoming_blocks();
+ if (!m_core.cleanup_handle_incoming_blocks())
+ {
+ LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks");
+ return 1;
+ }
m_block_queue.remove_spans(span_connection_id, start_height);
diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp
index 12f7c5fa4..9df698547 100644
--- a/src/daemon/command_server.cpp
+++ b/src/daemon/command_server.cpp
@@ -231,7 +231,7 @@ t_command_server::t_command_server(
m_command_lookup.set_handler(
"print_coinbase_tx_sum"
, std::bind(&t_command_parser_executor::print_coinbase_tx_sum, &m_parser, p::_1)
- , "Print sum of coinbase transactions (start height, block count)"
+ , "Print sum of coinbase transactions <start height> [block count]"
);
m_command_lookup.set_handler(
"alt_chain_info"
diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp
index 456eeee64..44d2dae43 100644
--- a/src/daemon/main.cpp
+++ b/src/daemon/main.cpp
@@ -142,7 +142,7 @@ int main(int argc, char const * argv[])
epee::debug::g_test_dbg_lock_sleep() = command_line::get_arg(vm, command_line::arg_test_dbg_lock_sleep);
- std::string db_type = command_line::get_arg(vm, command_line::arg_db_type);
+ std::string db_type = command_line::get_arg(vm, cryptonote::arg_db_type);
// verify that blockchaindb type is valid
if(!cryptonote::blockchain_valid_db_type(db_type))
diff --git a/src/debug_utilities/CMakeLists.txt b/src/debug_utilities/CMakeLists.txt
index e6d49fd61..99198dc57 100644
--- a/src/debug_utilities/CMakeLists.txt
+++ b/src/debug_utilities/CMakeLists.txt
@@ -37,7 +37,6 @@ monero_add_executable(cn_deserialize
target_link_libraries(cn_deserialize
LINK_PRIVATE
cryptonote_core
- common
blockchain_db
p2p
epee
diff --git a/src/p2p/net_peerlist_boost_serialization.h b/src/p2p/net_peerlist_boost_serialization.h
index 43c5ea5f0..6ea2d48fd 100644
--- a/src/p2p/net_peerlist_boost_serialization.h
+++ b/src/p2p/net_peerlist_boost_serialization.h
@@ -59,6 +59,8 @@ namespace boost
{
a & na.m_ip;
a & na.m_port;
+ if (!typename Archive::is_saving())
+ na.init_ids();
}
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 479adcafc..857e2af6e 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -391,6 +391,61 @@ bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vec
return true;
}
+bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ if (!try_connect_to_daemon())
+ {
+ fail_msg_writer() << tr("Cannot connect to daemon");
+ return true;
+ }
+ const uint64_t per_kb_fee = m_wallet->get_per_kb_fee();
+ const uint64_t typical_size_kb = 13;
+ message_writer() << (boost::format(tr("Current fee is %s monero per kB")) % print_money(per_kb_fee)).str();
+
+ std::vector<uint64_t> fees;
+ for (uint32_t priority = 1; priority <= 4; ++priority)
+ {
+ uint64_t mult = m_wallet->get_fee_multiplier(priority);
+ fees.push_back(per_kb_fee * typical_size_kb * mult);
+ }
+ std::vector<std::pair<uint64_t, uint64_t>> blocks;
+ try
+ {
+ uint64_t base_size = typical_size_kb * 1024;
+ blocks = m_wallet->estimate_backlog(base_size, base_size + 1023, fees);
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << tr("Error: failed to estimate backlog array size: ") << e.what();
+ return true;
+ }
+ if (blocks.size() != 4)
+ {
+ fail_msg_writer() << tr("Error: bad estimated backlog array size");
+ return true;
+ }
+
+ for (uint32_t priority = 1; priority <= 4; ++priority)
+ {
+ uint64_t nblocks_low = blocks[priority - 1].first;
+ uint64_t nblocks_high = blocks[priority - 1].second;
+ if (nblocks_low > 0)
+ {
+ std::string msg;
+ if (priority == m_wallet->get_default_priority() || (m_wallet->get_default_priority() == 0 && priority == 2))
+ msg = tr(" (current)");
+ uint64_t minutes_low = nblocks_low * DIFFICULTY_TARGET_V2 / 60, minutes_high = nblocks_high * DIFFICULTY_TARGET_V2 / 60;
+ if (nblocks_high == nblocks_low)
+ message_writer() << (boost::format(tr("%u block (%u minutes) backlog at priority %u%s")) % nblocks_low % minutes_low % priority % msg).str();
+ else
+ message_writer() << (boost::format(tr("%u to %u block (%u to %u minutes) backlog at priority %u")) % nblocks_low % nblocks_high % minutes_low % minutes_high % priority).str();
+ }
+ else
+ message_writer() << tr("No backlog at priority ") << priority;
+ }
+ return true;
+}
+
bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -722,6 +777,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("show_transfer", boost::bind(&simple_wallet::show_transfer, this, _1), tr("Show information about a transfer to/from this address"));
m_cmd_binder.set_handler("password", boost::bind(&simple_wallet::change_password, this, _1), tr("Change wallet password"));
m_cmd_binder.set_handler("payment_id", boost::bind(&simple_wallet::payment_id, this, _1), tr("Generate a new random full size payment id - these will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids"));
+ m_cmd_binder.set_handler("fee", boost::bind(&simple_wallet::print_fee_info, this, _1), tr("Print information about fee and current transaction backlog"));
m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help"));
}
//----------------------------------------------------------------------------------------------------
@@ -2431,6 +2487,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
break;
default:
LOG_ERROR("Unknown transfer method, using original");
+ /* FALLTHRU */
case TransferOriginal:
ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_trusted_daemon);
break;
@@ -2461,9 +2518,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
try
{
- uint64_t nblocks = m_wallet->estimate_backlog(size, fee);
- if (nblocks > 0)
- prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks).str();
+ std::vector<std::pair<uint64_t, uint64_t>> nblocks = m_wallet->estimate_backlog(size, size, {fee});
+ if (nblocks.size() != 1)
+ {
+ prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ }
+ else
+ {
+ if (nblocks[0].first > 0)
+ prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No)")) % nblocks[0].first).str();
+ }
}
catch (const std::exception &e)
{
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index eac4cbc99..079fae9f5 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -175,6 +175,7 @@ namespace cryptonote
bool show_transfer(const std::vector<std::string> &args);
bool change_password(const std::vector<std::string>& args);
bool payment_id(const std::vector<std::string> &args);
+ bool print_fee_info(const std::vector<std::string> &args);
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp
index c0974f880..7afc1f449 100644
--- a/src/wallet/api/wallet.cpp
+++ b/src/wallet/api/wallet.cpp
@@ -379,7 +379,32 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
const cryptonote::account_public_address address = m_wallet->get_account().get_keys().m_account_address;
try {
+ // Generate view only wallet
view_wallet->generate(path, password, address, viewkey);
+
+ // Export/Import outputs
+ auto outputs = m_wallet->export_outputs();
+ view_wallet->import_outputs(outputs);
+
+ // Copy scanned blockchain
+ auto bc = m_wallet->export_blockchain();
+ view_wallet->import_blockchain(bc);
+
+ // copy payments
+ auto payments = m_wallet->export_payments();
+ view_wallet->import_payments(payments);
+
+ // copy confirmed outgoing payments
+ std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>> out_payments;
+ m_wallet->get_payments_out(out_payments, 0);
+ view_wallet->import_payments_out(out_payments);
+
+ // Export/Import key images
+ // We already know the spent status from the outputs we exported, thus no need to check them again
+ auto key_images = m_wallet->export_key_images();
+ uint64_t spent = 0;
+ uint64_t unspent = 0;
+ view_wallet->import_key_images(key_images,spent,unspent,false);
m_status = Status_Ok;
} catch (const std::exception &e) {
LOG_ERROR("Error creating view only wallet: " << e.what());
@@ -387,6 +412,8 @@ bool WalletImpl::createWatchOnly(const std::string &path, const std::string &pas
m_errorString = e.what();
return false;
}
+ // Store wallet
+ view_wallet->store();
return true;
}
@@ -862,6 +889,11 @@ bool WalletImpl::exportKeyImages(const string &filename)
bool WalletImpl::importKeyImages(const string &filename)
{
+ if (!trustedDaemon()) {
+ m_status = Status_Error;
+ m_errorString = tr("Key images can only be imported with a trusted daemon");
+ return false;
+ }
try
{
uint64_t spent = 0, unspent = 0;
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 09ca8efe1..323a3a7fe 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -3457,12 +3457,15 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal
return true;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm) const
+uint64_t wallet2::get_fee_multiplier(uint32_t priority, int fee_algorithm)
{
static const uint64_t old_multipliers[3] = {1, 2, 3};
static const uint64_t new_multipliers[3] = {1, 20, 166};
static const uint64_t newer_multipliers[4] = {1, 4, 20, 166};
+ if (fee_algorithm == -1)
+ fee_algorithm = get_fee_algorithm();
+
// 0 -> default (here, x1 till fee algorithm 2, x4 from it)
if (priority == 0)
priority = m_default_priority;
@@ -5098,6 +5101,9 @@ uint64_t wallet2::get_approximate_blockchain_height() const
const int seconds_per_block = DIFFICULTY_TARGET_V2;
// Calculated blockchain height
uint64_t approx_blockchain_height = fork_block + (time(NULL) - fork_time)/seconds_per_block;
+ // testnet got some huge rollbacks, so the estimation is way off
+ if (m_testnet && approx_blockchain_height > 105000)
+ approx_blockchain_height -= 105000;
LOG_PRINT_L2("Calculated blockchain height: " << approx_blockchain_height);
return approx_blockchain_height;
}
@@ -5330,7 +5336,7 @@ uint64_t wallet2::import_key_images(const std::string &filename, uint64_t &spent
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent)
+uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent)
{
COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
@@ -5379,34 +5385,88 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
m_transfers[n].m_key_image_known = true;
}
- m_daemon_rpc_mutex.lock();
- bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
- m_daemon_rpc_mutex.unlock();
- THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
- THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
- THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
- "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
- std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
-
+ if(check_spent)
+ {
+ m_daemon_rpc_mutex.lock();
+ bool r = epee::net_utils::invoke_http_json("/is_key_image_spent", req, daemon_resp, m_http_client, rpc_timeout);
+ m_daemon_rpc_mutex.unlock();
+ THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent");
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent");
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status);
+ THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != signed_key_images.size(), error::wallet_internal_error,
+ "daemon returned wrong response for is_key_image_spent, wrong amounts count = " +
+ std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(signed_key_images.size()));
+ for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
+ {
+ transfer_details &td = m_transfers[n];
+ td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
+ }
+ }
spent = 0;
unspent = 0;
- for (size_t n = 0; n < daemon_resp.spent_status.size(); ++n)
+ for(size_t i = 0; i < m_transfers.size(); ++i)
{
- transfer_details &td = m_transfers[n];
+ transfer_details &td = m_transfers[i];
uint64_t amount = td.amount();
- td.m_spent = daemon_resp.spent_status[n] != COMMAND_RPC_IS_KEY_IMAGE_SPENT::UNSPENT;
if (td.m_spent)
spent += amount;
else
unspent += amount;
- LOG_PRINT_L2("Transfer " << n << ": " << print_money(amount) << " (" << td.m_global_output_index << "): "
- << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[n] << ")");
+ LOG_PRINT_L2("Transfer " << i << ": " << print_money(amount) << " (" << td.m_global_output_index << "): "
+ << (td.m_spent ? "spent" : "unspent") << " (key image " << req.key_images[i] << ")");
}
- LOG_PRINT_L1("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
-
+ MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
return m_transfers[signed_key_images.size() - 1].m_block_height;
}
+wallet2::payment_container wallet2::export_payments() const
+{
+ payment_container payments;
+ for (auto const &p : m_payments)
+ {
+ payments.emplace(p);
+ }
+ return payments;
+}
+void wallet2::import_payments(const payment_container &payments)
+{
+ m_payments.clear();
+ for (auto const &p : payments)
+ {
+ m_payments.emplace(p);
+ }
+}
+void wallet2::import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments)
+{
+ m_confirmed_txs.clear();
+ for (auto const &p : confirmed_payments)
+ {
+ m_confirmed_txs.emplace(p);
+ }
+}
+
+std::vector<crypto::hash> wallet2::export_blockchain() const
+{
+ std::vector<crypto::hash> bc;
+ for (auto const &b : m_blockchain)
+ {
+ bc.push_back(b);
+ }
+ return bc;
+}
+
+void wallet2::import_blockchain(const std::vector<crypto::hash> &bc)
+{
+ m_blockchain.clear();
+ for (auto const &b : bc)
+ {
+ m_blockchain.push_back(b);
+ }
+ cryptonote::block genesis;
+ generate_genesis(genesis);
+ crypto::hash genesis_hash = get_block_hash(genesis);
+ check_genesis(genesis_hash);
+ m_local_bc_height = m_blockchain.size();
+}
//----------------------------------------------------------------------------------------------------
std::vector<tools::wallet2::transfer_details> wallet2::export_outputs() const
{
@@ -5747,10 +5807,14 @@ bool wallet2::is_synced() const
return get_blockchain_current_height() >= height;
}
//----------------------------------------------------------------------------------------------------
-uint64_t wallet2::estimate_backlog(uint64_t blob_size, uint64_t fee)
+std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector<uint64_t> &fees)
{
- THROW_WALLET_EXCEPTION_IF(blob_size == 0, error::wallet_internal_error, "Invalid 0 fee");
- THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
+ THROW_WALLET_EXCEPTION_IF(min_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee");
+ THROW_WALLET_EXCEPTION_IF(max_blob_size == 0, error::wallet_internal_error, "Invalid 0 fee");
+ for (uint64_t fee: fees)
+ {
+ THROW_WALLET_EXCEPTION_IF(fee == 0, error::wallet_internal_error, "Invalid 0 fee");
+ }
// get txpool backlog
epee::json_rpc::request<cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request> req = AUTO_VAL_INIT(req);
@@ -5776,27 +5840,35 @@ uint64_t wallet2::estimate_backlog(uint64_t blob_size, uint64_t fee)
THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info");
THROW_WALLET_EXCEPTION_IF(resp_t.result.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info");
THROW_WALLET_EXCEPTION_IF(resp_t.result.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error);
+ uint64_t full_reward_zone = resp_t.result.block_size_limit / 2;
- double our_fee_byte = fee / (double)blob_size;
- uint64_t priority_size = 0;
- for (const auto &i: res.result.backlog)
+ std::vector<std::pair<uint64_t, uint64_t>> blocks;
+ for (uint64_t fee: fees)
{
- if (i.blob_size == 0)
+ double our_fee_byte_min = fee / (double)min_blob_size, our_fee_byte_max = fee / (double)max_blob_size;
+ uint64_t priority_size_min = 0, priority_size_max = 0;
+ for (const auto &i: res.result.backlog)
{
- MWARNING("Got 0 sized blob from txpool, ignored");
- continue;
+ if (i.blob_size == 0)
+ {
+ MWARNING("Got 0 sized blob from txpool, ignored");
+ continue;
+ }
+ double this_fee_byte = i.fee / (double)i.blob_size;
+ if (this_fee_byte >= our_fee_byte_min)
+ priority_size_min += i.blob_size;
+ if (this_fee_byte >= our_fee_byte_max)
+ priority_size_max += i.blob_size;
}
- double this_fee_byte = i.fee / (double)i.blob_size;
- if (this_fee_byte < our_fee_byte)
- continue;
- priority_size += i.blob_size;
- }
- uint64_t full_reward_zone = resp_t.result.block_size_limit / 2;
- uint64_t nblocks = (priority_size + full_reward_zone - 1) / full_reward_zone;
- MDEBUG("estimate_backlog: priority_size " << priority_size << " for " << our_fee_byte << " (" << our_fee_byte << " piconero fee/byte), "
- << nblocks << " blocks at block size " << full_reward_zone);
- return nblocks;
+ uint64_t nblocks_min = (priority_size_min + full_reward_zone - 1) / full_reward_zone;
+ uint64_t nblocks_max = (priority_size_max + full_reward_zone - 1) / full_reward_zone;
+ MDEBUG("estimate_backlog: priority_size " << priority_size_min << " - " << priority_size_max << " for " << fee
+ << " (" << our_fee_byte_min << " - " << our_fee_byte_max << " piconero byte fee), "
+ << nblocks_min << " - " << nblocks_max << " blocks at block size " << full_reward_zone);
+ blocks.push_back(std::make_pair(nblocks_min, nblocks_max));
+ }
+ return blocks;
}
//----------------------------------------------------------------------------------------------------
void wallet2::generate_genesis(cryptonote::block& b) {
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index f30c97635..adf03abcc 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -582,12 +582,17 @@ namespace tools
std::string sign(const std::string &data) const;
bool verify(const std::string &data, const cryptonote::account_public_address &address, const std::string &signature) const;
+ // Import/Export wallet data
std::vector<tools::wallet2::transfer_details> export_outputs() const;
size_t import_outputs(const std::vector<tools::wallet2::transfer_details> &outputs);
-
+ payment_container export_payments() const;
+ void import_payments(const payment_container &payments);
+ void import_payments_out(const std::list<std::pair<crypto::hash,wallet2::confirmed_transfer_details>> &confirmed_payments);
+ std::vector<crypto::hash> export_blockchain() const;
+ void import_blockchain(const std::vector<crypto::hash> &bc);
bool export_key_images(const std::string filename);
std::vector<std::pair<crypto::key_image, crypto::signature>> export_key_images() const;
- uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent);
+ uint64_t import_key_images(const std::vector<std::pair<crypto::key_image, crypto::signature>> &signed_key_images, uint64_t &spent, uint64_t &unspent, bool check_spent = true);
uint64_t import_key_images(const std::string &filename, uint64_t &spent, uint64_t &unspent);
void update_pool_state(bool refreshed = false);
@@ -604,7 +609,10 @@ namespace tools
bool is_synced() const;
- uint64_t estimate_backlog(uint64_t blob_size, uint64_t fee);
+ std::vector<std::pair<uint64_t, uint64_t>> estimate_backlog(uint64_t min_blob_size, uint64_t max_blob_size, const std::vector<uint64_t> &fees);
+
+ uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm = -1);
+ uint64_t get_per_kb_fee();
private:
/*!
@@ -646,9 +654,7 @@ namespace tools
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
uint64_t get_upper_transaction_size_limit();
std::vector<uint64_t> get_unspent_amounts_vector();
- uint64_t get_fee_multiplier(uint32_t priority, int fee_algorithm) const;
uint64_t get_dynamic_per_kb_fee_estimate();
- uint64_t get_per_kb_fee();
float get_output_relatedness(const transfer_details &td0, const transfer_details &td1) const;
std::vector<size_t> pick_preferred_rct_inputs(uint64_t needed_money) const;
void set_spent(size_t idx, uint64_t height);