aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/wallet2.cpp137
-rw-r--r--src/wallet/wallet2.h14
-rw-r--r--src/wallet/wallet_rpc_server.cpp41
-rw-r--r--src/wallet/wallet_rpc_server.h3
4 files changed, 106 insertions, 89 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 5ab1ff85e..81472687d 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -846,6 +846,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
td.m_key_image = ki[o];
td.m_key_image_known = !m_watch_only;
td.m_amount = tx.vout[o].amount;
+ td.m_pk_index = pk_index - 1;
if (td.m_amount == 0)
{
td.m_mask = mask[o];
@@ -894,6 +895,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, const s
td.m_tx = (const cryptonote::transaction_prefix&)tx;
td.m_txid = txid();
td.m_amount = tx.vout[o].amount;
+ td.m_pk_index = pk_index - 1;
if (td.m_amount == 0)
{
td.m_mask = mask[o];
@@ -1573,35 +1575,12 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
std::list<cryptonote::block_complete_entry> blocks;
std::vector<COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> o_indices;
- std::string daemon_height_err = "";
- uint64_t daemon_bc_height = get_daemon_blockchain_height(daemon_height_err);
- if(daemon_height_err.size() > 0) {
- throw std::runtime_error(daemon_height_err);
- }
-
// pull the first set of blocks
get_short_chain_history(short_chain_history);
m_run.store(true, std::memory_order_relaxed);
if (start_height > m_blockchain.size() || m_refresh_from_block_height > m_blockchain.size()) {
-
- // even target_height can be zero if the daemon just started and hasn't gotten some sync
- // data back from peers .. hmmm, what to do ... O.o (you can see him thinking)
- // i'm going with infiniti loop until i get something bigger than zero or err ... moneromoo don't kill me
- std::string daemon_target_err = "";
- uint64_t daemon_target_height = 0;
-
- while(daemon_target_height == 0)
- {
- daemon_target_height = get_daemon_blockchain_target_height(daemon_target_err);
- if(daemon_target_err.size() > 0) {
- daemon_target_height = get_approximate_blockchain_height(); // - x?
- }
- }
-
- if (m_refresh_from_block_height > daemon_target_height) m_refresh_from_block_height = daemon_target_height - 1;
- if (!start_height) start_height = m_refresh_from_block_height;
- if (start_height >= daemon_bc_height) start_height = daemon_bc_height - 1;
-
+ if (!start_height)
+ start_height = m_refresh_from_block_height;
// we can shortcut by only pulling hashes up to the start_height
fast_refresh(start_height, blocks_start_height, short_chain_history);
// regenerate the history now that we've got a full set of hashes
@@ -1611,56 +1590,53 @@ void wallet2::refresh(uint64_t start_height, uint64_t & blocks_fetched, bool& re
// and then fall through to regular refresh processing
}
- if(!(m_refresh_from_block_height >= daemon_bc_height))
- {
- pull_blocks(start_height, blocks_start_height, short_chain_history, blocks, o_indices);
- // always reset start_height to 0 to force short_chain_ history to be used on
- // subsequent pulls in this refresh.
- start_height = 0;
+ pull_blocks(start_height, blocks_start_height, short_chain_history, blocks, o_indices);
+ // always reset start_height to 0 to force short_chain_ history to be used on
+ // subsequent pulls in this refresh.
+ start_height = 0;
- while(m_run.load(std::memory_order_relaxed))
+ while(m_run.load(std::memory_order_relaxed))
+ {
+ try
{
- try
- {
- // pull the next set of blocks while we're processing the current one
- uint64_t next_blocks_start_height;
- std::list<cryptonote::block_complete_entry> next_blocks;
- std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> next_o_indices;
- bool error = false;
- pull_thread = boost::thread([&]{pull_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, next_blocks, next_o_indices, error);});
-
- process_blocks(blocks_start_height, blocks, o_indices, added_blocks);
- blocks_fetched += added_blocks;
- pull_thread.join();
- if(!added_blocks)
- break;
+ // pull the next set of blocks while we're processing the current one
+ uint64_t next_blocks_start_height;
+ std::list<cryptonote::block_complete_entry> next_blocks;
+ std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> next_o_indices;
+ bool error = false;
+ pull_thread = boost::thread([&]{pull_next_blocks(start_height, next_blocks_start_height, short_chain_history, blocks, next_blocks, next_o_indices, error);});
+
+ process_blocks(blocks_start_height, blocks, o_indices, added_blocks);
+ blocks_fetched += added_blocks;
+ pull_thread.join();
+ if(!added_blocks)
+ break;
- // switch to the new blocks from the daemon
- blocks_start_height = next_blocks_start_height;
- blocks = next_blocks;
- o_indices = next_o_indices;
+ // switch to the new blocks from the daemon
+ blocks_start_height = next_blocks_start_height;
+ blocks = next_blocks;
+ o_indices = next_o_indices;
- // handle error from async fetching thread
- if (error)
- {
- throw std::runtime_error("proxy exception in refresh thread");
- }
+ // handle error from async fetching thread
+ if (error)
+ {
+ throw std::runtime_error("proxy exception in refresh thread");
}
- catch (const std::exception&)
+ }
+ catch (const std::exception&)
+ {
+ blocks_fetched += added_blocks;
+ if (pull_thread.joinable())
+ pull_thread.join();
+ if(try_count < 3)
{
- blocks_fetched += added_blocks;
- if (pull_thread.joinable())
- pull_thread.join();
- if(try_count < 3)
- {
- LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
- ++try_count;
- }
- else
- {
- LOG_ERROR("pull_blocks failed, try_count=" << try_count);
- throw;
- }
+ LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")...");
+ ++try_count;
+ }
+ else
+ {
+ LOG_ERROR("pull_blocks failed, try_count=" << try_count);
+ throw;
}
}
}
@@ -3623,7 +3599,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
*it_to_replace = real_oe;
- src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx);
+ src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
src.real_output = it_to_replace - src.outputs.begin();
src.real_output_in_tx_index = td.m_internal_output_index;
detail::print_source_entry(src);
@@ -3699,6 +3675,9 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
uint64_t upper_transaction_size_limit = get_upper_tranaction_size_limit();
uint64_t needed_money = fee;
LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money));
+ LOG_PRINT_L0("selected transfers: ");
+ for (auto t: selected_transfers)
+ LOG_PRINT_L2(" " << t);
// calculate total amount being sent to all destinations
// throw if total amount overflows uint64_t
@@ -3759,7 +3738,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
real_oe.second.dest = rct::pk2rct(boost::get<txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key);
real_oe.second.mask = rct::commit(td.amount(), td.m_mask);
*it_to_replace = real_oe;
- src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx);
+ src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index);
src.real_output = it_to_replace - src.outputs.begin();
src.real_output_in_tx_index = td.m_internal_output_index;
src.mask = td.m_mask;
@@ -3770,12 +3749,22 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry
// we still keep a copy, since we want to keep dsts free of change for user feedback purposes
std::vector<cryptonote::tx_destination_entry> splitted_dsts = dsts;
cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts);
- if (needed_money < found_money)
+ change_dts.amount = found_money - needed_money;
+ if (change_dts.amount == 0)
+ {
+ // If the change is 0, send it to a random address, to avoid confusing
+ // the sender with a 0 amount output. We send a 0 amount in order to avoid
+ // letting the destination be able to work out which of the inputs is the
+ // real one in our rings
+ cryptonote::account_base dummy;
+ dummy.generate();
+ change_dts.addr = dummy.get_keys().m_account_address;
+ }
+ else
{
change_dts.addr = m_account.get_keys().m_account_address;
- change_dts.amount = found_money - needed_money;
- splitted_dsts.push_back(change_dts);
}
+ splitted_dsts.push_back(change_dts);
crypto::secret_key tx_key;
bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time, tx_key, true);
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index dcb6367d1..616b74edb 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -129,6 +129,7 @@ namespace tools
uint64_t m_amount;
bool m_rct;
bool m_key_image_known;
+ size_t m_pk_index;
bool is_rct() const { return m_rct; }
uint64_t amount() const { return m_amount; }
@@ -147,6 +148,7 @@ namespace tools
FIELD(m_amount)
FIELD(m_rct)
FIELD(m_key_image_known)
+ FIELD(m_pk_index)
END_SERIALIZE()
};
@@ -644,7 +646,7 @@ namespace tools
};
}
BOOST_CLASS_VERSION(tools::wallet2, 15)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 6)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 7)
BOOST_CLASS_VERSION(tools::wallet2::payment_details, 1)
BOOST_CLASS_VERSION(tools::wallet2::unconfirmed_transfer_details, 6)
BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 3)
@@ -677,6 +679,10 @@ namespace boost
{
x.m_key_image_known = true;
}
+ if (ver < 7)
+ {
+ x.m_pk_index = 0;
+ }
}
template <class Archive>
@@ -738,6 +744,12 @@ namespace boost
return;
}
a & x.m_key_image_known;
+ if (ver < 7)
+ {
+ initialize_transfer_details(a, x, ver);
+ return;
+ }
+ a & x.m_pk_index;
}
template <class Archive>
diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp
index 5352b0b73..7c08bbe4b 100644
--- a/src/wallet/wallet_rpc_server.cpp
+++ b/src/wallet/wallet_rpc_server.cpp
@@ -27,6 +27,7 @@
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
+#include <boost/asio/ip/address.hpp>
#include <cstdint>
#include "include_base_utils.h"
using namespace epee;
@@ -47,6 +48,8 @@ namespace
const command_line::arg_descriptor<std::string, true> arg_rpc_bind_port = {"rpc-bind-port", "Sets bind port for server"};
const command_line::arg_descriptor<std::string> arg_rpc_bind_ip = {"rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1"};
const command_line::arg_descriptor<std::string> arg_user_agent = {"user-agent", "Restrict RPC to clients using this user agent", ""};
+
+ const command_line::arg_descriptor<bool> arg_confirm_external_bind = {"confirm-external-bind", "Confirm rcp-bind-ip value is NOT a loopback (local) IP"};
}
namespace tools
@@ -84,20 +87,35 @@ namespace tools
return epee::http_server_impl_base<wallet_rpc_server, connection_context>::run(1, true);
}
//------------------------------------------------------------------------------------------------------------------------------
- bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm)
- {
- m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
- m_port = command_line::get_arg(vm, arg_rpc_bind_port);
- m_user_agent = command_line::get_arg(vm, arg_user_agent);
- return true;
- }
- //------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::init(const boost::program_options::variables_map& vm)
{
+ std::string bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
+ if (!bind_ip.empty())
+ {
+ // always parse IP here for error consistency
+ boost::system::error_code ec{};
+ const auto parsed_ip = boost::asio::ip::address::from_string(bind_ip, ec);
+ if (ec)
+ {
+ LOG_ERROR(tr("Invalid IP address given for rpc-bind-ip argument"));
+ return false;
+ }
+
+ if (!parsed_ip.is_loopback() && !command_line::get_arg(vm, arg_confirm_external_bind))
+ {
+ LOG_ERROR(
+ tr("The rpc-bind-ip value is listening for unencrypted external connections. Consider SSH tunnel or SSL proxy instead. Override with --confirm-external-bind")
+ );
+ return false;
+ }
+ }
+
m_net_server.set_threads_prefix("RPC");
- bool r = handle_command_line(vm);
- CHECK_AND_ASSERT_MES(r, false, "Failed to process command line in core_rpc_server");
- return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(m_port, m_bind_ip, m_user_agent);
+ return epee::http_server_impl_base<wallet_rpc_server, connection_context>::init(
+ command_line::get_arg(vm, arg_rpc_bind_port),
+ std::move(bind_ip),
+ command_line::get_arg(vm, arg_user_agent)
+ );
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er)
@@ -1115,6 +1133,7 @@ int main(int argc, char** argv) {
command_line::add_arg(desc_params, arg_rpc_bind_ip);
command_line::add_arg(desc_params, arg_rpc_bind_port);
command_line::add_arg(desc_params, arg_user_agent);
+ command_line::add_arg(desc_params, arg_confirm_external_bind);
command_line::add_arg(desc_params, arg_wallet_file);
command_line::add_arg(desc_params, arg_from_json);
diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h
index 7d6f94e56..96ca1af04 100644
--- a/src/wallet/wallet_rpc_server.h
+++ b/src/wallet/wallet_rpc_server.h
@@ -118,9 +118,6 @@ namespace tools
bool on_query_key(const wallet_rpc::COMMAND_RPC_QUERY_KEY::request& req, wallet_rpc::COMMAND_RPC_QUERY_KEY::response& res, epee::json_rpc::error& er);
wallet2& m_wallet;
- std::string m_port;
- std::string m_bind_ip;
- std::string m_user_agent;
std::atomic<bool> m_stop;
};
}