Compare commits

...

56 Commits

Author SHA1 Message Date
jw
d4a5778dd6 Merge pull request #113 from wowario/walletfix
revert wallet2: use a gamma distribution to pick fake outs
2018-10-27 07:41:11 -07:00
jw
cce5708153 Merge pull request #112 from wowario/checkpoints
update checkpoints
2018-10-27 07:40:51 -07:00
wowario
0a97b3784d revert wallet2: use a gamma distribution to pick fake outs 2018-10-27 10:00:43 +03:00
wowario
a8790e240c update checkpoints 2018-10-25 19:14:26 +03:00
jw
c929c2a6bb Merge pull request #111 from wowario/lwma3
add LWMA v3 for v10 HF
2018-10-24 16:53:08 -07:00
jw
741adad93a Merge pull request #110 from wowario/subadd
rpc wallet: revert integrated address generation
2018-10-24 16:52:56 -07:00
jw
73b17fcb62 Merge pull request #109 from wowario/lwma
difficulty: remove testnet variables
2018-10-24 16:52:46 -07:00
wowario
f3ee225f29 add lwma3 2018-10-24 20:29:35 +03:00
wowario
f165101429 rpc wallet: revert integrated address generation 2018-10-24 14:37:54 +03:00
wowario
d2554341b1 difficulty: remove testnet variables 2018-10-24 13:03:02 +03:00
jw
c1632fb30c Merge pull request #108 from wowario/txpool_fix
tx_pool: revert #4592 and move bin2hex conversion to on_get_transaction_pool
2018-10-23 17:57:53 -07:00
stoffu
17cd68f865 tx_pool: revert #4592 and move bin2hex conversion to on_get_transaction_pool 2018-10-23 19:46:13 +03:00
jw
5c6eb96036 Merge pull request #107 from wowario/lwma2
Difficulty: increase minimum to 25m
2018-10-23 03:41:03 -07:00
jw
b67c96af71 Merge pull request #106 from wowario/version
up version to 0.3.1
2018-10-23 03:40:51 -07:00
wowario
88fd5fb494 increase minimum difficulty to 25 million 2018-10-22 23:40:29 +03:00
wowario
5c3195dac9 up version to 0.3.1 2018-10-22 23:30:04 +03:00
jw
8386c6df2c Merge pull request #105 from wowario/upstream
Upstream
2018-10-22 09:12:39 -07:00
wowario
9d952da3a0 Merge branch 'release-v0.3.0.0' into upstream 2018-10-22 16:01:04 +00:00
jw
2320fb5549 Merge pull request #104 from wowario/release-v0.3.0.0
Wallet: encourage use of subaddresses
2018-10-22 08:21:42 -07:00
moneromooo-monero
b40a81c694 wallet2: use a gamma distribution to pick fake outs
as per "An Empirical Analysis of Linkability in the Monero
Blockchain", by Miller et al.
2018-10-20 21:09:50 +03:00
stoffu
308a8f69ad daemon.print_bc: don't print difficulty twice 2018-10-20 21:09:50 +03:00
moneromooo-monero
b491ff61c5 epee: set jsonrpc to "2.0" in parse error return data 2018-10-20 21:09:49 +03:00
rbrunner7
bb0ac27a4a simplewallet: correct number of human-readable months 2018-10-20 21:09:49 +03:00
moneromooo-monero
835caf3722 simplewallet: add a warning and prompt on rescan_blockchain
Many people are using this as a "let's see what this does" command
when something doesn't work as they thought it should, and thus
destroying info that they might still need.
2018-10-20 21:09:49 +03:00
fireice-uk
9021fe99b1 node_rpc_proxy: fix fork earliest height caching [RYO backport]
xref https://github.com/ryo-currency/ryo-currency/pull/86
2018-10-20 21:09:49 +03:00
rbrunner7
bbd251c48f simplewallet: Simplify LOCK_IDLE_SCOPE macro 2018-10-20 21:09:49 +03:00
moneromooo-monero
00c6056e98 simplewallet: allow named priority levels for default-priority
to match those used by the various transfer functions
2018-10-20 21:09:49 +03:00
moneromooo-monero
47f7cf68ae epee: resize vectors where possible in serialization
to avoid unnecessary repeated reallocation
2018-10-20 21:09:49 +03:00
moneromooo-monero
c4bdd5699c epee: some speedup in parsing 2018-10-20 21:09:48 +03:00
moneromooo-monero
7e6b4601c3 tx_pool: fix infinite loop when failing to find a meta record 2018-10-20 21:09:48 +03:00
stoffu
d4f07b40de wallet2.get_reserve_proof: throw when specified amount is zero 2018-10-20 21:09:48 +03:00
moneromooo-monero
1bbfeb325c tx_pool: fix tx removal at startup keeping references 2018-10-20 19:49:28 +03:00
moneromooo-monero
dc1e56d815 daemon: do not display uptime when not known 2018-10-20 19:49:27 +03:00
moneromooo-monero
332ac6a03a rpc: return "already mining" in start_mining if already mining 2018-10-20 16:07:51 +03:00
moneromooo-monero
ae255e3857 cryptonote_format_utils: do not early out on invalid tx pubkeys
Another such pubkey might be valid
2018-10-20 10:43:03 +03:00
stoffu
7cf07e9319 simplewallet: make sure wallet config is stored right after creation 2018-10-20 10:43:02 +03:00
moneromooo-monero
d904ea08a1 wallet2: avoid using arbitrary random values when unknown 2018-10-20 10:43:02 +03:00
moneromooo-monero
0da1f14aaf wallet2: guard against bad outputs in import_outputs
also some minor speedup
2018-10-20 10:43:02 +03:00
moneromooo-monero
583eaf3ccb wallet2: fix O(n^2) behaviour in import_key_images
That takes a lot of time for even not so large wallets
2018-10-20 10:43:02 +03:00
stoffu
ee45ef2c9e simplewallet.unspent_outputs: fix wrong logic for parsing 2018-10-20 10:43:02 +03:00
stoffu
7ba6d69196 wallet-rpc: filter getbalance response by address index 2018-10-20 10:43:02 +03:00
stoffu
83e5d6a829 wallet-rpc: add get_address_index command 2018-10-20 10:43:02 +03:00
Jorropo
a09d5ea211 [monerod] Added blocks remaining count during syncronisation.
And percent if usefull (% < 99)
2018-10-20 10:43:01 +03:00
stoffu
2998b929d5 tx_pool: store hex string instead of raw binary to tx_blob of get_transaction_pool RPC
Inspired by https://github.com/masari-project/masari/issues/93
2018-10-20 10:43:01 +03:00
doy-lee
44e0f9eebf wallet2: clear found out for every tx key
Avoids triggering the sanity check
2018-10-20 10:43:01 +03:00
moneromooo-monero
00bf0b5ef0 wallet_rpc_server: include all transfer records for a txid
Since subaddresses were added, a tx can now create more than
one payment
2018-10-20 10:43:01 +03:00
wowario
d1176c5ef5 rpc: added subaddresses warning 2018-10-18 12:39:44 +03:00
wowario
cbf07f01ba encourage use of subaddresses 2018-10-17 22:37:19 +03:00
jw
9c828a281b Merge pull request #100 from wowario/release-v0.3.1.0
update checkpoints
2018-10-11 08:50:09 -07:00
wowario
a5253e2fb4 update checkpoints 2018-10-09 15:30:06 +03:00
jw
ff3a667a90 Merge pull request #98 from wowario/release-v0.3.1.0
compile fix for Ubuntu 18
2018-10-05 21:50:20 -07:00
wowario
a3a84378eb bump version to 0.3.0.1 2018-10-05 20:59:58 +03:00
xiphon
202d568676 build: fix gcc false positive 'stringop-overflow' warning 2018-10-05 20:57:41 +03:00
jw
47aa3f296d Merge pull request #97 from camthegeek/windows-fix5102018
unbound submodule update
2018-10-05 10:39:51 -07:00
wowario
6bdd11abe2 rename to wownero 2018-10-05 20:32:27 +03:00
camthegeek
6486269929 unbound submodule update 2018-10-05 12:12:28 -04:00
30 changed files with 390 additions and 238 deletions

View File

@@ -95,7 +95,7 @@ Dates are provided in the format YYYY-MM-DD.
| ------------------------------ | -----------| ----------------- | ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| 1 | 2018-04-01 | v7 | v0.1.0.0 | v0.1.0.0 | Cryptonight variant 1, ringsize >= 8, sorted inputs
| 6969 | 2018-04-24 | v8 | v0.2.0.0 | v0.2.0.0 | Bulletproofs, LWMA difficulty algorithm, ringsize >= 10, reduce unlock to 4
| 53666 | 2018-10-06 | v9 | v0.3.0.0 | v0.3.0.0 | Cryptonight variant 2, LWMA v2, ringsize = 22, XXX
| 53666 | 2018-10-06 | v9 | v0.3.0.0 | v0.3.1.0 | Cryptonight variant 2, LWMA v2, ringsize = 22, XXX
X's indicate that these details have not been determined as of commit date.

View File

@@ -122,6 +122,7 @@
if(!ps.load_from_json(query_info.m_body)) \
{ \
boost::value_initialized<epee::json_rpc::error_response> rsp; \
static_cast<epee::json_rpc::error_response&>(rsp).jsonrpc = "2.0"; \
static_cast<epee::json_rpc::error_response&>(rsp).error.code = -32700; \
static_cast<epee::json_rpc::error_response&>(rsp).error.message = "Parse error"; \
epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp), response_info.m_body); \

View File

@@ -35,6 +35,11 @@
namespace epee
{
namespace
{
template<class C> void hint_resize(C &container, size_t size) {}
template<class C> void hint_resize(std::vector<C> &container, size_t size) { container.reserve(size); }
}
namespace serialization
{
@@ -158,6 +163,7 @@ namespace epee
false,
"size in blob " << loaded_size << " not have not zero modulo for sizeof(value_type) = " << sizeof(typename stl_container::value_type));
size_t count = (loaded_size/sizeof(typename stl_container::value_type));
hint_resize(container, count);
for(size_t i = 0; i < count; i++)
container.insert(container.end(), *(pelem++));
}

View File

@@ -28,6 +28,8 @@
#pragma once
#include <algorithm>
namespace epee
{
namespace misc_utils
@@ -36,8 +38,12 @@ namespace misc_utils
{
inline std::string transform_to_escape_sequence(const std::string& src)
{
//std::stringstream res;
static const char escaped[] = "\b\f\n\r\t\v\"\\/";
if (std::find_first_of(src.begin(), src.end(), escaped, escaped + sizeof(escaped)) == src.end())
return src;
std::string res;
res.reserve(2 * src.size());
for(std::string::const_iterator it = src.begin(); it!=src.end(); ++it)
{
switch(*it)
@@ -84,6 +90,7 @@ namespace misc_utils
inline void match_string2(std::string::const_iterator& star_end_string, std::string::const_iterator buf_end, std::string& val)
{
val.clear();
val.reserve(std::distance(star_end_string, buf_end));
bool escape_mode = false;
std::string::const_iterator it = star_end_string;
++it;

Binary file not shown.

View File

@@ -185,7 +185,13 @@ namespace cryptonote
ADD_CHECKPOINT(20000, "52cc7edcb49eb02f28a653b824089a726f4050eb210263ee6f4180d388a1e5cc");
ADD_CHECKPOINT(30000, "d22fde5dd240ade16d3250eb0aa5d1c16dc7cb51c20484e05eb274911032b3fa");
ADD_CHECKPOINT(40000, "aee0d642322542ba069cb1c58ab2acd3560f108d4682c3dc3cb15a54d442d91f");
ADD_CHECKPOINT(50000, "5286ac2a0f39b3aefcba363cd71f2760bd1e0d763cbc81026ebdc3f80a86541f");
ADD_CHECKPOINT(50000, "5286ac2a0f39b3aefcba363cd71f2760bd1e0d763cbc81026ebdc3f80a86541f");
ADD_CHECKPOINT(53666, "3f43f56f66ef0c43cf2fd14d0d28fa2aae0ef8f40716773511345750770f1255"); //Hard fork to v9
ADD_CHECKPOINT(54500, "8ed3078b389c2b44add007803d741b58d3fbed2e1ba4139bda702152d8773c9b");
ADD_CHECKPOINT(55000, "4b662ceccefc3247edb4d654dd610b8fb496e85b88a5de43cc2bdd28171b15ff");
ADD_CHECKPOINT(57000, "08a79f09f12bb5d230b63963356a760d51618e526cfc636047a6f3798217c177");
ADD_CHECKPOINT(59000, "180b51ee2c5fbcd4362eb7a29df9422481310dd77d10bccdf8930724c31e007e");
return true;
}

View File

@@ -201,15 +201,25 @@ namespace cryptonote
{
crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation);
bool r = hwdev.generate_key_derivation(tx_public_key, ack.m_view_secret_key, recv_derivation);
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
if (!r)
{
MWARNING("key image helper: failed to generate_key_derivation(" << tx_public_key << ", " << ack.m_view_secret_key << ")");
memcpy(&recv_derivation, rct::identity().bytes, sizeof(recv_derivation));
}
std::vector<crypto::key_derivation> additional_recv_derivations;
for (size_t i = 0; i < additional_tx_public_keys.size(); ++i)
{
crypto::key_derivation additional_recv_derivation = AUTO_VAL_INIT(additional_recv_derivation);
r = hwdev.generate_key_derivation(additional_tx_public_keys[i], ack.m_view_secret_key, additional_recv_derivation);
CHECK_AND_ASSERT_MES(r, false, "key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
additional_recv_derivations.push_back(additional_recv_derivation);
if (!r)
{
MWARNING("key image helper: failed to generate_key_derivation(" << additional_tx_public_keys[i] << ", " << ack.m_view_secret_key << ")");
}
else
{
additional_recv_derivations.push_back(additional_recv_derivation);
}
}
boost::optional<subaddress_receive_info> subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev);

View File

@@ -256,14 +256,10 @@ namespace cryptonote {
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= static_cast<uint64_t>(N+1) );
if ( cryptonote::MAINNET && height <= DIFFICULTY_HEIGHT ){
if ( height <= DIFFICULTY_HEIGHT ){
return static_cast<uint64_t>(DIFFICULTY_GUESS);
}
if ( cryptonote::TESTNET && height <= DIFFICULTY_TESTNET_HEIGHT ){
return static_cast<uint64_t>(DIFFICULTY_TESTNET_GUESS);
}
for ( int64_t i = 1; i <= N; i++ ) {
ST = static_cast<int64_t>(timestamps[i]) - static_cast<int64_t>(timestamps[i-1]);
ST = std::max(-4*T, std::min(ST, 6*T));
@@ -281,14 +277,50 @@ namespace cryptonote {
next_D = std::max(next_D,(prev_D*108)/100);
}
if ( cryptonote::MAINNET && next_D < DIFFICULTY_MINIMUM ) {
if ( next_D < DIFFICULTY_MINIMUM ) {
return static_cast<uint64_t>(DIFFICULTY_MINIMUM);
}
else if ( cryptonote::TESTNET && next_D < DIFFICULTY_TESTNET_MINIMUM ) {
return static_cast<uint64_t>(DIFFICULTY_TESTNET_MINIMUM);
}
else {
return static_cast<uint64_t>(next_D);
}
}
// LWMA-3 difficulty algorithm
// Copyright (c) 2017-2018 Zawy, MIT License
difficulty_type next_difficulty_v4(std::vector<uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height) {
uint64_t T = DIFFICULTY_TARGET_V2;
uint64_t N = DIFFICULTY_WINDOW_V2;
uint64_t L(0), ST, sum_3_ST(0), next_D, prev_D, this_timestamp, previous_timestamp;
assert(timestamps.size() == cumulative_difficulties.size() && timestamps.size() <= N+1 );
if ( height == DIFFICULTY_HEIGHT_V2 ){
return static_cast<uint64_t>(DIFFICULTY_GUESS);
}
previous_timestamp = timestamps[0];
for ( uint64_t i = 1; i <= N; i++) {
if ( timestamps[i] > previous_timestamp ) {
this_timestamp = timestamps[i];
} else { this_timestamp = previous_timestamp+1; }
ST = std::min(6*T ,this_timestamp - previous_timestamp);
previous_timestamp = this_timestamp;
L += ST * i ;
if ( i > N-3 ) { sum_3_ST += ST; }
}
next_D = ((cumulative_difficulties[N] - cumulative_difficulties[0])*T*(N+1)*99)/(100*2*L);
prev_D = cumulative_difficulties[N] - cumulative_difficulties[N-1];
next_D = std::max((prev_D*67)/100, std::min(next_D, (prev_D*150)/100));
if ( sum_3_ST < (8*T)/10) { next_D = std::max(next_D,(prev_D*108)/100); }
if ( next_D < DIFFICULTY_MINIMUM ) {
return static_cast<uint64_t>(DIFFICULTY_MINIMUM);
}
else {
return static_cast<uint64_t>(next_D);
}
}
}

View File

@@ -55,4 +55,5 @@ namespace cryptonote
difficulty_type next_difficulty(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v2(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t target_seconds);
difficulty_type next_difficulty_v3(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height);
difficulty_type next_difficulty_v4(std::vector<std::uint64_t> timestamps, std::vector<difficulty_type> cumulative_difficulties, size_t height);
}

View File

@@ -48,6 +48,7 @@
#define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2
#define CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE 4
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 11
#define BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW 60
// MONEY_SUPPLY - total number coins to be generated
@@ -82,11 +83,9 @@
#define DIFFICULTY_BLOCKS_COUNT_V2 DIFFICULTY_WINDOW_V2 + 1 // added +1 to make N=N
#define DIFFICULTY_BLOCKS_COUNT DIFFICULTY_WINDOW + DIFFICULTY_LAG
#define DIFFICULTY_HEIGHT 53666 // v9 fork height
#define DIFFICULTY_HEIGHT_V2 777777 // v10 fork height
#define DIFFICULTY_GUESS 40000000 // difficulty at fork 40m
#define DIFFICULTY_MINIMUM 10000000 // minimum difficulty set to 10m
#define DIFFICULTY_TESTNET_HEIGHT 100
#define DIFFICULTY_TESTNET_GUESS 5069
#define DIFFICULTY_TESTNET_MINIMUM 4069
#define DIFFICULTY_MINIMUM 25000000 // minimum difficulty set to 25m
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V1 DIFFICULTY_TARGET_V1 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS
#define CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS_V2 DIFFICULTY_TARGET_V2 * CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS

View File

@@ -838,8 +838,11 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
else if (version == 8) {
return next_difficulty_v2(timestamps, difficulties, target);
}
else {
else if (version == 9) {
return next_difficulty_v3(timestamps, difficulties, height);
}
else {
return next_difficulty_v4(timestamps, difficulties, height);
}
}
//------------------------------------------------------------------
@@ -1056,9 +1059,12 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std:
}
else if (version == 8) {
return next_difficulty_v2(timestamps, cumulative_difficulties, target);
}
}
else if (version == 9) {
return next_difficulty_v2(timestamps, cumulative_difficulties, height);
}
else {
return next_difficulty_v3(timestamps, cumulative_difficulties, height);
return next_difficulty_v4(timestamps, cumulative_difficulties, height);
}
}
@@ -1350,12 +1356,13 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m
bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vector<uint64_t>& timestamps)
{
LOG_PRINT_L3("Blockchain::" << __func__);
if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
const uint8_t hf_version = m_hardfork->get_current_version();
size_t blockchain_timestamp_check_window = hf_version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(timestamps.size() >= blockchain_timestamp_check_window)
return true;
CRITICAL_REGION_LOCAL(m_blockchain_lock);
size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size();
size_t need_elements = blockchain_timestamp_check_window - timestamps.size();
CHECK_AND_ASSERT_MES(start_top_height < m_db->height(), false, "internal error: passed start_height not < " << " m_db->height() -- " << start_top_height << " >= " << m_db->height());
size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements : 0;
while (start_top_height != stop_offset)
@@ -3203,10 +3210,12 @@ bool Blockchain::check_block_timestamp(std::vector<uint64_t>& timestamps, const
{
LOG_PRINT_L3("Blockchain::" << __func__);
median_ts = epee::misc_utils::median(timestamps);
const uint8_t hf_version = m_hardfork->get_current_version();
size_t blockchain_timestamp_check_window = hf_version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(b.timestamp < median_ts)
{
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts);
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << blockchain_timestamp_check_window << " blocks, " << median_ts);
return false;
}
@@ -3224,6 +3233,8 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
{
LOG_PRINT_L3("Blockchain::" << __func__);
uint64_t cryptonote_block_future_time_limit = get_current_hard_fork_version() >= 8 ? CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT_V2 : CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT;
const uint8_t hf_version = m_hardfork->get_current_version();
size_t blockchain_timestamp_check_window = hf_version >= 10 ? BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW_V2 : BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
if(b.timestamp > get_adjusted_time() + cryptonote_block_future_time_limit)
{
MERROR_VER("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 10 minutes");
@@ -3231,7 +3242,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
}
// if not enough blocks, no proper median yet, return true
if(m_db->height() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
if(m_db->height() < blockchain_timestamp_check_window)
{
return true;
}
@@ -3240,7 +3251,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons
auto h = m_db->height();
// need most recent 60 blocks, get index of first of those
size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW;
size_t offset = h - blockchain_timestamp_check_window;
for(;offset < h; ++offset)
{
timestamps.push_back(m_db->get_block_timestamp(offset));
@@ -4441,7 +4452,7 @@ void Blockchain::cancel()
}
#if defined(PER_BLOCK_CHECKPOINT)
static const char expected_block_hashes_hash[] = "16cb7e839284c1910925f8d9f8a752f38ad908ae9deec7afdfbbc4a777f5ef2e";
static const char expected_block_hashes_hash[] = "897d3ae0f3aef8ef8362b0bb3535925738414fa78d9146f8a04c60555fa5a95f";
void Blockchain::load_compiled_in_block_hashes()
{
const bool testnet = m_nettype == TESTNET;

View File

@@ -127,7 +127,7 @@ namespace cryptonote
out_amounts[1] += out_amounts[0];
for (size_t n = 1; n < out_amounts.size(); ++n)
out_amounts[n - 1] = out_amounts[n];
out_amounts.resize(out_amounts.size() - 1);
out_amounts.pop_back();
}
}
else

View File

@@ -1095,7 +1095,7 @@ namespace cryptonote
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())
for (; sorted_it != m_txs_by_fee_and_receive_time.end(); ++sorted_it)
{
txpool_tx_meta_t meta;
if (!m_blockchain.get_txpool_tx_meta(sorted_it->second, meta))
@@ -1109,7 +1109,6 @@ namespace cryptonote
if (max_total_size < total_size + meta.blob_size)
{
LOG_PRINT_L2(" would exceed maximum block size");
sorted_it++;
continue;
}
@@ -1122,14 +1121,12 @@ namespace cryptonote
if(!get_block_reward(median_size, total_size + meta.blob_size, already_generated_coins, block_reward, version))
{
LOG_PRINT_L2(" would exceed maximum block size");
sorted_it++;
continue;
}
coinbase = block_reward + fee + meta.fee;
if (coinbase < template_accept_threshold(best_coinbase))
{
LOG_PRINT_L2(" would decrease coinbase to " << print_money(coinbase));
sorted_it++;
continue;
}
}
@@ -1173,13 +1170,11 @@ namespace cryptonote
if (!ready)
{
LOG_PRINT_L2(" not ready to go");
sorted_it++;
continue;
}
if (have_key_images(k_images, tx))
{
LOG_PRINT_L2(" key images already seen");
sorted_it++;
continue;
}
@@ -1188,7 +1183,6 @@ namespace cryptonote
fee += meta.fee;
best_coinbase = coinbase;
append_key_images(k_images, tx);
sorted_it++;
LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase));
}
@@ -1284,6 +1278,7 @@ namespace cryptonote
{
MWARNING("Failed to parse tx from txpool, removing");
remove.push_back(txid);
return true;
}
if (!insert_key_images(tx, meta.kept_by_block))
{

View File

@@ -1167,8 +1167,20 @@ skip:
+ " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued";
if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info"))
timing_message += std::string(": ") + m_block_queue.get_overview();
MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height()
if(m_core.get_target_blockchain_height() == 0){
MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height()
<< timing_message);
} else {
const int completition_percent = (m_core.get_current_blockchain_height() * 100 / m_core.get_target_blockchain_height());
if(completition_percent < 99) {//printing completion percent only if % is < of 99 cause for 99 >= this is useless
MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height()
<< " (" << completition_percent << "% " << (m_core.get_target_blockchain_height() - m_core.get_current_blockchain_height())
<< " blocks remaining)" << timing_message);
} else {
MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height()
<< timing_message);
}
}
}
}
}
@@ -1752,3 +1764,4 @@ skip:
m_core.stop();
}
} // namespace

View File

@@ -661,7 +661,7 @@ bool t_command_parser_executor::sync_info(const std::vector<std::string>& args)
bool t_command_parser_executor::version(const std::vector<std::string>& args)
{
std::cout << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << std::endl;
std::cout << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << std::endl;
return true;
}

View File

@@ -438,7 +438,8 @@ bool t_rpc_command_executor::show_status() {
}
}
tools::success_msg_writer() << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections, uptime %ud %uh %um %us")
std::stringstream str;
str << boost::format("Height: %llu/%llu (%.1f%%) on %s%s, %s, net hash %s, v%u%s, %s, %u(out)+%u(in) connections")
% (unsigned long long)ires.height
% (unsigned long long)net_height
% get_sync_percentage(ires)
@@ -451,12 +452,21 @@ bool t_rpc_command_executor::show_status() {
% (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked")
% (unsigned)ires.outgoing_connections_count
% (unsigned)ires.incoming_connections_count
% (unsigned int)floor(uptime / 60.0 / 60.0 / 24.0)
% (unsigned int)floor(fmod((uptime / 60.0 / 60.0), 24.0))
% (unsigned int)floor(fmod((uptime / 60.0), 60.0))
% (unsigned int)fmod(uptime, 60.0)
;
// restricted RPC does not disclose start time
if (ires.start_time)
{
str << boost::format(", uptime %ud %uh %um %us")
% (unsigned int)floor(uptime / 60.0 / 60.0 / 24.0)
% (unsigned int)floor(fmod((uptime / 60.0 / 60.0), 24.0))
% (unsigned int)floor(fmod((uptime / 60.0), 60.0))
% (unsigned int)fmod(uptime, 60.0)
;
}
tools::success_msg_writer() << str.str();
return true;
}
@@ -554,7 +564,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u
if (!first)
std::cout << std::endl;
std::cout
<< "height: " << header.height << ", timestamp: " << header.timestamp << ", difficulty: " << header.difficulty
<< "height: " << header.height << ", timestamp: " << header.timestamp
<< ", size: " << header.block_size << ", transactions: " << header.num_txes << std::endl
<< "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl
<< "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl

View File

@@ -863,7 +863,13 @@ namespace cryptonote
boost::thread::attributes attrs;
attrs.set_stack_size(THREAD_STACK_SIZE);
if(!m_core.get_miner().start(info.address, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
cryptonote::miner &miner= m_core.get_miner();
if (miner.is_mining())
{
res.status = "Already mining";
return true;
}
if(!miner.start(info.address, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
{
res.status = "Failed, mining not started";
LOG_PRINT_L0(res.status);
@@ -992,6 +998,8 @@ namespace cryptonote
return r;
m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
for (tx_info& txi : res.transactions)
txi.tx_blob = epee::string_tools::buff_to_hex_nodelimer(txi.tx_blob);
res.status = CORE_RPC_STATUS_OK;
return true;
}

View File

@@ -93,13 +93,8 @@ typedef cryptonote::simple_wallet sw;
m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \
/* stop any background refresh, and take over */ \
m_wallet->stop(); \
m_idle_mutex.lock(); \
while (m_auto_refresh_refreshing) \
m_idle_cond.notify_one(); \
m_idle_mutex.unlock(); \
/* if (auto_refresh_run)*/ \
/*m_auto_refresh_thread.join();*/ \
boost::unique_lock<boost::mutex> lock(m_idle_mutex); \
m_idle_cond.notify_all(); \
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \
m_auto_refresh_enabled.store(auto_refresh_enabled, std::memory_order_relaxed); \
})
@@ -525,6 +520,18 @@ bool parse_priority(const std::string& arg, uint32_t& priority)
return false;
}
std::string join_priority_strings(const char *delimiter)
{
std::string s;
for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
{
if (!s.empty())
s += delimiter;
s += allowed_priority_strings[n];
}
return s;
}
std::string simple_wallet::get_commands_str()
{
std::stringstream ss;
@@ -1560,7 +1567,7 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
bool simple_wallet::version(const std::vector<std::string> &args)
{
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
message_writer() << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
return true;
}
@@ -1611,12 +1618,12 @@ bool simple_wallet::set_store_tx_info(const std::vector<std::string> &args/* = s
bool simple_wallet::set_default_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
int priority = 0;
uint32_t priority = 0;
try
{
if (strchr(args[1].c_str(), '-'))
{
fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4 ");
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
if (args[1] == "0")
@@ -1625,11 +1632,23 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
else
{
priority = boost::lexical_cast<int>(args[1]);
if (priority < 1 || priority > 4)
bool found = false;
for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
{
fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
return true;
if (allowed_priority_strings[n] == args[1])
{
found = true;
priority = n;
}
}
if (!found)
{
priority = boost::lexical_cast<int>(args[1]);
if (priority < 1 || priority > 4)
{
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
}
}
@@ -1643,7 +1662,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
catch(const boost::bad_lexical_cast &)
{
fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
catch(...)
@@ -1688,13 +1707,13 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
return true;
}
bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
bool simple_wallet::set_confirm_subaddress(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
parse_bool_and_use(args[1], [&](bool r) {
m_wallet->confirm_missing_payment_id(r);
m_wallet->confirm_subaddress(r);
m_wallet->rewrite(m_wallet_file, pwd_container->password());
});
}
@@ -1931,10 +1950,10 @@ bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<st
"Commands:\n" <<
tr(" \"balance\" - Show balance.\n") <<
tr(" \"address\" - Show wallet's address.\n") <<
tr(" \"integrated_address\" - Show receiving address with an integrated payment ID.\n") <<
tr(" \"transfer [address|integrated_address] [amount]\" - Send WOW to an address.\n") <<
tr(" \"address new [optional note]\" - Create new sub-address with optional note, spaces are allowed.\n") <<
tr(" \"address all\" - Show all sub-addresses.\n") <<
tr(" \"transfer [address] [amount]\" - Send WOW to an address.\n") <<
tr(" \"show_transfers [in|out|pending|failed|pool]\" - Show transactions.\n") <<
tr(" \"payments [payment ID]\" - Show transaction of a given payment ID.\n") <<
tr(" \"sweep_all [address]\" - Send whole balance to another wallet.\n") <<
tr(" \"seed\" - Show secret 25 words that can be used to recover this wallet.\n") <<
tr(" \"refresh\" - Synchronize wallet with the Wownero network.\n") <<
@@ -2064,13 +2083,9 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::print_address, this, _1),
tr("address [ new <label text with white spaces allowed> | all | <index_min> [<index_max>] | label <index> <label text with white spaces allowed>]"),
tr("If no arguments are specified or <index> is specified, the wallet shows the default or specified address. If \"all\" is specified, the wallet shows all the existing addresses in the currently selected account. If \"new \" is specified, the wallet creates a new address with the provided label text (which can be empty). If \"label\" is specified, the wallet sets the label of the address specified by <index> to the provided label text."));
m_cmd_binder.set_handler("integrated_address",
boost::bind(&simple_wallet::print_integrated_address, this, _1),
tr("integrated_address [<payment_id> | <address>]"),
tr("Encode a payment ID into an integrated address for the current wallet public address (no argument uses a random payment ID), or decode an integrated address to standard address and payment ID"));
m_cmd_binder.set_handler("address_book",
boost::bind(&simple_wallet::address_book, this, _1),
tr("address_book [(add ((<address> [pid <id>])|<integrated address>) [<description possibly with whitespaces>])|(delete <index>)]"),
tr("address_book [(add ((<address> [pid <id>])) [<description possibly with whitespaces>])|(delete <index>)]"),
tr("Print all entries in the address book, optionally adding/deleting an entry to/from it."));
m_cmd_binder.set_handler("save",
boost::bind(&simple_wallet::save, this, _1),
@@ -2182,7 +2197,7 @@ simple_wallet::simple_wallet()
tr("Show the unspent outputs of a specified address within an optional amount range."));
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
tr("Rescan the blockchain from scratch."));
tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
tr("set_tx_note <txid> [free text note]"),
@@ -2312,6 +2327,10 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
std::string seed_language = m_wallet->get_seed_language();
if (m_use_english_language_names)
seed_language = crypto::ElectrumWords::get_english_name_for(seed_language);
std::string priority_string = "invalid";
uint32_t priority = m_wallet->get_default_priority();
if (priority < allowed_priority_strings.size())
priority_string = allowed_priority_strings[priority];
success_msg_writer() << "seed = " << seed_language;
success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers();
success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members();
@@ -2319,7 +2338,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh();
success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type());
success_msg_writer() << "priority = " << m_wallet->get_default_priority();
success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id();
success_msg_writer() << "confirm-subaddress = " << m_wallet->confirm_subaddress();
success_msg_writer() << "ask-password = " << m_wallet->ask_password();
success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point());
success_msg_writer() << "min-outputs-count = " << m_wallet->get_min_output_count();
@@ -2373,7 +2392,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)"));
CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4"));
CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("confirm-subaddress", set_confirm_subaddress, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("wownero, millinero, micronero, nanonero, piconero"));
CHECK_SIMPLE_VARIABLE("min-outputs-count", set_min_output_count, tr("unsigned integer"));
@@ -2631,6 +2650,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
}
}
epee::wipeable_string password;
if (!m_generate_from_view_key.empty())
{
m_wallet_file = m_generate_from_view_key;
@@ -2683,8 +2703,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
bool r = new_wallet(vm, info.address, boost::none, viewkey);
auto r = new_wallet(vm, info.address, boost::none, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
}
else if (!m_generate_from_spend_key.empty())
{
@@ -2702,8 +2723,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("failed to parse spend key secret key");
return false;
}
bool r = new_wallet(vm, m_recovery_key, true, false, "");
auto r = new_wallet(vm, m_recovery_key, true, false, "");
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
}
else if (!m_generate_from_keys.empty())
{
@@ -2780,8 +2802,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("view key does not match standard address");
return false;
}
bool r = new_wallet(vm, info.address, spendkey, viewkey);
auto r = new_wallet(vm, info.address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
}
// Asks user for all the data required to merge secret keys from multisig wallets into one master wallet, which then gets full control of the multisig wallet. The resulting wallet will be the same as any other regular wallet.
@@ -2914,8 +2937,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// create wallet
bool r = new_wallet(vm, info.address, spendkey, viewkey);
auto r = new_wallet(vm, info.address, spendkey, viewkey);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
}
else if (!m_generate_from_json.empty())
@@ -2937,8 +2961,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_device;
// create wallet
bool r = new_wallet(vm, "Ledger");
auto r = new_wallet(vm, "Ledger");
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
// if no block_height is specified, assume its a new account and start it "now"
if(m_wallet->get_refresh_from_block_height() == 0) {
{
@@ -2963,12 +2988,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
m_wallet_file = m_generate_new;
bool r;
boost::optional<epee::wipeable_string> r;
if (m_restore_multisig_wallet)
r = new_wallet(vm, multisig_keys, old_language);
else
r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language);
CHECK_AND_ASSERT_MES(r, false, tr("account creation failed"));
password = *r;
}
if (m_restoring && m_generate_from_json.empty() && m_generate_from_device.empty())
@@ -3050,6 +3076,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
m_wallet->set_refresh_from_block_height(m_restore_height);
}
m_wallet->rewrite(m_wallet_file, password);
}
else
{
@@ -3217,15 +3244,16 @@ boost::optional<tools::password_container> simple_wallet::get_and_verify_passwor
return pwd_container;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const crypto::secret_key& recovery_key, bool recover, bool two_random, const std::string &old_language)
{
auto rc = tools::wallet2::make_new(vm, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
return false;
return {};
}
epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3261,7 +3289,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
}
mnemonic_language = get_mnemonic_language();
if (mnemonic_language.empty())
return false;
return {};
}
m_wallet->set_seed_language(mnemonic_language);
@@ -3279,7 +3307,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
return false;
return {};
}
// convert rng value to electrum-style word list
@@ -3305,10 +3333,10 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
}
success_msg_writer() << "**********************************************************************";
return true;
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const cryptonote::account_public_address& address, const boost::optional<crypto::secret_key>& spendkey,
const crypto::secret_key& viewkey)
{
@@ -3316,8 +3344,9 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
m_wallet = std::move(rc.first);
if (!m_wallet)
{
return false;
return {};
}
epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3347,22 +3376,23 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
return false;
return {};
}
return true;
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const std::string &device_name) {
auto rc = tools::wallet2::make_new(vm, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
return false;
return {};
}
epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3383,21 +3413,22 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
return false;
return {};
}
return true;
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
const std::string &multisig_keys, const std::string &old_language)
{
auto rc = tools::wallet2::make_new(vm, password_prompter);
m_wallet = std::move(rc.first);
if (!m_wallet)
{
return false;
return {};
}
epee::wipeable_string password = rc.second.password();
if (!m_subaddress_lookahead.empty())
{
@@ -3427,7 +3458,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
if (!m_wallet->multisig(&ready, &threshold, &total) || !ready)
{
fail_msg_writer() << tr("failed to generate new mutlisig wallet");
return false;
return {};
}
message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total
<< m_wallet->get_account().get_public_address_str(m_wallet->nettype());
@@ -3435,10 +3466,10 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm,
catch (const std::exception& e)
{
fail_msg_writer() << tr("failed to generate new wallet: ") << e.what();
return false;
return {};
}
return true;
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
@@ -3470,6 +3501,8 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
prefix = tr("Opened wallet");
message_writer(console_color_white, true) <<
prefix << ": " << m_wallet->get_account().get_public_address_str(m_wallet->nettype());
message_writer(console_color_yellow, true) << "\n" << tr("When receiving WOW, "
"create a new sub-address for each transaction with the command “address new”. \nUse “address all” to see all sub-addresses.\n");
if (m_wallet->get_account().get_device()) {
message_writer(console_color_white, true) << "Wallet is on device: " << m_wallet->get_account().get_device().get_name();
}
@@ -4346,7 +4379,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
success_msg_writer() << tr("WARNING: Payment id is unencrypted, which might potentially compromise your privacy. An integrated address is recommended instead.\n");
success_msg_writer() << tr("\nWARNING: Payment IDs will be deprecated soon. Sub-addresses are recommended instead.\n");
}
else
{
@@ -4357,6 +4390,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::string extra_nonce;
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
success_msg_writer() << tr("\nWARNING: Payment IDs will be deprecated soon. Sub-addresses are recommended instead.\n");
}
}
@@ -4433,10 +4467,10 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
dsts.push_back(de);
}
// prompt is there is no payment id and confirmation is required
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
// prompt if regular address
if (!payment_id_seen && m_wallet->confirm_subaddress() && dsts.size() > num_subaddresses)
{
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
std::string accepted = input_line(tr("\nSending to a regular address may degrade privacy. Ask recipient for a sub-address instead. Continue anyway? (Y/Yes/N/No): "));
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -4833,6 +4867,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
payment_id_seen = true;
success_msg_writer() << tr("\nWARNING: Payment IDs will be deprecated soon. Sub-addresses are recommended instead.\n");
}
else
{
@@ -4844,6 +4879,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
payment_id_seen = true;
success_msg_writer() << tr("\nWARNING: Payment IDs will be deprecated soon. Sub-addresses are recommended instead.\n");
}
}
@@ -4882,10 +4918,10 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a
payment_id_seen = true;
}
// prompt is there is no payment id and confirmation is required
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
// prompt if regular address
if (!payment_id_seen && m_wallet->confirm_subaddress() && !info.is_subaddress)
{
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
std::string accepted = input_line(tr("\nSending to a regular address may degrade privacy. Ask recipient for a sub-address instead. Continue anyway? (Y/Yes/N/No): "));
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5081,10 +5117,10 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
payment_id_seen = true;
}
// prompt if there is no payment id and confirmation is required
if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
// prompt if regular address
if (!payment_id_seen && m_wallet->confirm_subaddress() && !info.is_subaddress)
{
std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
std::string accepted = input_line(tr("\nSending to a regular address may degrade privacy. Ask recipient for a sub-address instead. Continue anyway? (Y/Yes/N/No): "));
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5971,7 +6007,7 @@ static std::string get_human_readable_timespan(std::chrono::seconds seconds)
if (ts < 3600 * 24 * 30.5)
return std::to_string((uint64_t)(ts / (3600 * 24))) + tr(" days");
if (ts < 3600 * 24 * 365.25)
return std::to_string((uint64_t)(ts / (3600 * 24 * 365.25))) + tr(" months");
return std::to_string((uint64_t)(ts / (3600 * 24 * 30.5))) + tr(" months");
return tr("a long time");
}
//----------------------------------------------------------------------------------------------------
@@ -6167,7 +6203,7 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
auto local_args = args_;
std::set<uint32_t> subaddr_indices;
if (local_args.size() > 0 && local_args[0].substr(0, 6) != "index=")
if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=")
{
if (!parse_subaddress_indices(local_args[0], subaddr_indices))
return true;
@@ -6297,6 +6333,14 @@ bool simple_wallet::unspent_outputs(const std::vector<std::string> &args_)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain.");
message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc");
std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): "));
if(!std::cin.eof())
{
if (!command_line::is_yes(confirm))
return true;
}
return refresh_main(0, true);
}
//----------------------------------------------------------------------------------------------------
@@ -6675,56 +6719,7 @@ bool simple_wallet::print_address(const std::vector<std::string> &args/* = std::
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::print_integrated_address(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
crypto::hash8 payment_id;
if (args.size() > 1)
{
fail_msg_writer() << tr("usage: integrated_address [payment ID]");
return true;
}
if (args.size() == 0)
{
if (m_current_subaddress_account != 0)
{
fail_msg_writer() << tr("Integrated addresses can only be created for account 0");
return true;
}
payment_id = crypto::rand<crypto::hash8>();
success_msg_writer() << tr("Random payment ID: ") << payment_id;
success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype());
return true;
}
if(tools::wallet2::parse_short_payment_id(args.back(), payment_id))
{
if (m_current_subaddress_account != 0)
{
fail_msg_writer() << tr("Integrated addresses can only be created for account 0");
return true;
}
success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->nettype());
return true;
}
else {
address_parse_info info;
if(get_account_address_from_str(info, m_wallet->nettype(), args.back()))
{
if (info.has_payment_id)
{
success_msg_writer() << boost::format(tr("Integrated address: %s, payment ID: %s")) %
get_account_address_as_str(m_wallet->nettype(), false, info.address) % epee::string_tools::pod_to_hex(info.payment_id);
}
else
{
success_msg_writer() << (info.is_subaddress ? tr("Subaddress: ") : tr("Standard address: ")) << get_account_address_as_str(m_wallet->nettype(), info.is_subaddress, info.address);
}
return true;
}
}
fail_msg_writer() << tr("failed to parse payment ID or address");
return true;
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if (args.size() == 0)
@@ -6732,7 +6727,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
}
else if (args.size() == 1 || (args[0] != "add" && args[0] != "delete"))
{
fail_msg_writer() << tr("usage: address_book [(add (<address> [pid <long or short payment id>])|<integrated address> [<description possibly with whitespaces>])|(delete <index>)]");
fail_msg_writer() << tr("usage: address_book [(add (<address> [pid <long or short payment id>]) [<description possibly with whitespaces>])|(delete <index>)]");
return true;
}
else if (args[0] == "add")

View File

@@ -91,13 +91,13 @@ namespace cryptonote
//! \return Prompts user for password and verifies against local file. Logs on error and returns `none`
boost::optional<tools::password_container> get_and_verify_password() const;
bool new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const crypto::secret_key& recovery_key,
bool recover, bool two_random, const std::string &old_language);
bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address,
const boost::optional<crypto::secret_key>& spendkey, const crypto::secret_key& viewkey);
bool new_wallet(const boost::program_options::variables_map& vm,
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
const std::string &multisig_keys, const std::string &old_language);
bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name);
bool open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
@@ -121,7 +121,7 @@ namespace cryptonote
bool set_store_tx_info(const std::vector<std::string> &args = std::vector<std::string>());
bool set_auto_refresh(const std::vector<std::string> &args = std::vector<std::string>());
bool set_refresh_type(const std::vector<std::string> &args = std::vector<std::string>());
bool set_confirm_missing_payment_id(const std::vector<std::string> &args = std::vector<std::string>());
bool set_confirm_subaddress(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ask_password(const std::vector<std::string> &args = std::vector<std::string>());
bool set_unit(const std::vector<std::string> &args = std::vector<std::string>());
bool set_min_output_count(const std::vector<std::string> &args = std::vector<std::string>());
@@ -167,7 +167,6 @@ namespace cryptonote
void print_accounts();
void print_accounts(const std::string& tag);
bool print_address(const std::vector<std::string> &args = std::vector<std::string>());
bool print_integrated_address(const std::vector<std::string> &args = std::vector<std::string>());
bool address_book(const std::vector<std::string> &args = std::vector<std::string>());
bool save(const std::vector<std::string> &args);
bool save_watch_only(const std::vector<std::string> &args);

View File

@@ -1,5 +1,5 @@
#define DEF_MONERO_VERSION_TAG "@VERSIONTAG@"
#define DEF_MONERO_VERSION "0.3.0.0-master"
#define DEF_MONERO_VERSION "0.3.1.0"
#define DEF_MONERO_RELEASE_NAME "Cool Cage"
#define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG

View File

@@ -744,14 +744,6 @@ std::string WalletImpl::address(uint32_t accountIndex, uint32_t addressIndex) co
return m_wallet->get_subaddress_as_str({accountIndex, addressIndex});
}
std::string WalletImpl::integratedAddress(const std::string &payment_id) const
{
crypto::hash8 pid;
if (!tools::wallet2::parse_short_payment_id(payment_id, pid)) {
return "";
}
return m_wallet->get_integrated_address_as_str(pid);
}
std::string WalletImpl::secretViewKey() const
{

View File

@@ -88,7 +88,6 @@ public:
std::string errorString() const;
bool setPassword(const std::string &password);
std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const;
std::string integratedAddress(const std::string &payment_id) const;
std::string secretViewKey() const;
std::string publicViewKey() const;
std::string secretSpendKey() const;

View File

@@ -373,16 +373,6 @@ struct Wallet
virtual void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const = 0;
//! check if hard fork rules should be used
virtual bool useForkRules(uint8_t version, int64_t early_blocks) const = 0;
/*!
* \brief integratedAddress - returns integrated address for current wallet address and given payment_id.
* if passed "payment_id" param is an empty string or not-valid payment id string
* (16 characters hexadecimal string) - random payment_id will be generated
*
* \param payment_id - 16 characters hexadecimal string or empty string if new random payment id needs to be
* generated
* \return - 106 characters string representing integrated address
*/
virtual std::string integratedAddress(const std::string &payment_id) const = 0;
/*!
* \brief secretViewKey - returns secret view key

View File

@@ -146,7 +146,7 @@ boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version,
CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon");
CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get hard fork status");
m_earliest_height[version] = resp_t.enabled ? resp_t.earliest_height : std::numeric_limits<uint64_t>::max();
m_earliest_height[version] = resp_t.earliest_height;
}
earliest_height = m_earliest_height[version];

View File

@@ -651,7 +651,7 @@ wallet2::wallet2(network_type nettype, bool restricted):
m_auto_refresh(true),
m_refresh_from_block_height(0),
m_explicit_refresh_from_block_height(true),
m_confirm_missing_payment_id(true),
m_confirm_subaddress(true),
m_confirm_non_default_ring_size(true),
m_ask_password(true),
m_min_output_count(0),
@@ -887,6 +887,14 @@ cryptonote::account_public_address wallet2::get_subaddress(const cryptonote::sub
return hwdev.get_subaddress(m_account.get_keys(), index);
}
//----------------------------------------------------------------------------------------------------
boost::optional<cryptonote::subaddress_index> wallet2::get_subaddress_index(const cryptonote::account_public_address& address) const
{
auto index = m_subaddresses.find(address.m_spend_public_key);
if (index == m_subaddresses.end())
return boost::none;
return index->second;
}
//----------------------------------------------------------------------------------------------------
crypto::public_key wallet2::get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const
{
hw::device &hwdev = m_account.get_device();
@@ -898,6 +906,7 @@ std::string wallet2::get_subaddress_as_str(const cryptonote::subaddress_index& i
cryptonote::account_public_address address = get_subaddress(index);
return cryptonote::get_account_address_as_str(m_nettype, !index.is_zero(), address);
}
//----------------------------------------------------------------------------------------------------
std::string wallet2::get_integrated_address_as_str(const crypto::hash8& payment_id) const
{
@@ -1105,7 +1114,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
// (that is, the prunable stuff may or may not be included)
if (!miner_tx && !pool)
process_unconfirmed(txid, tx, height);
std::vector<size_t> outs;
std::unordered_map<cryptonote::subaddress_index, uint64_t> tx_money_got_in_outs; // per receiving subaddress index
crypto::public_key tx_pub_key = null_pkey;
@@ -1123,6 +1131,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
uint64_t total_received_1 = 0;
while (!tx.vout.empty())
{
std::vector<size_t> outs;
// if tx.vout is not empty, we loop through all tx pubkeys
tx_extra_pub_key pub_key_field;
@@ -2623,8 +2632,8 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable
value2.SetUint64(m_refresh_from_block_height);
json.AddMember("refresh_height", value2, json.GetAllocator());
value2.SetInt(m_confirm_missing_payment_id ? 1 :0);
json.AddMember("confirm_missing_payment_id", value2, json.GetAllocator());
value2.SetInt(m_confirm_subaddress ? 1 :0);
json.AddMember("confirm_subaddress", value2, json.GetAllocator());
value2.SetInt(m_confirm_non_default_ring_size ? 1 :0);
json.AddMember("confirm_non_default_ring_size", value2, json.GetAllocator());
@@ -2734,7 +2743,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
m_default_priority = 0;
m_auto_refresh = true;
m_refresh_type = RefreshType::RefreshDefault;
m_confirm_missing_payment_id = true;
m_confirm_subaddress = true;
m_confirm_non_default_ring_size = true;
m_ask_password = true;
m_min_output_count = 0;
@@ -2837,8 +2846,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
}
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, refresh_height, uint64_t, Uint64, false, 0);
m_refresh_from_block_height = field_refresh_height;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_missing_payment_id, int, Int, false, true);
m_confirm_missing_payment_id = field_confirm_missing_payment_id;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_subaddress, int, Int, false, true);
m_confirm_subaddress = field_confirm_subaddress;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, confirm_non_default_ring_size, int, Int, false, true);
m_confirm_non_default_ring_size = field_confirm_non_default_ring_size;
GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ask_password, int, Int, false, true);
@@ -5914,6 +5923,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
bool is_shortly_after_segregation_fork = height >= segregation_fork_height && height < segregation_fork_height + SEGREGATION_FORK_VICINITY;
bool is_after_segregation_fork = height >= segregation_fork_height;
// get histogram for the amounts we need
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t);
cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t);
@@ -5985,6 +5995,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>>
COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req);
COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp);
size_t num_selected_transfers = 0;
for(size_t idx: selected_transfers)
{
@@ -8124,7 +8135,7 @@ bool wallet2::use_fork_rules(uint8_t version, int64_t early_blocks) const
result = m_node_rpc_proxy.get_earliest_height(version, earliest_height);
throw_on_rpc_response_error(result, "get_hard_fork_info");
bool close_enough = height >= earliest_height - early_blocks && earliest_height != std::numeric_limits<uint64_t>::max(); // start using the rules that many blocks beforehand
bool close_enough = height >= earliest_height - early_blocks; // start using the rules that many blocks beforehand
if (close_enough)
LOG_PRINT_L2("Using v" << (unsigned)version << " rules");
else
@@ -8907,6 +8918,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
if (account_minreserve)
{
THROW_WALLET_EXCEPTION_IF(account_minreserve->second == 0, error::wallet_internal_error, "Proved amount must be greater than 0");
// minimize the number of outputs included in the proof, by only picking the N largest outputs that can cover the requested min reserve amount
std::sort(selected_transfers.begin(), selected_transfers.end(), [&](const size_t a, const size_t b)
{ return m_transfers[a].amount() > m_transfers[b].amount(); });
@@ -9572,6 +9584,17 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
std::unordered_set<crypto::hash> spent_txids; // For each spent key image, search for a tx in m_transfers that uses it as input.
std::vector<size_t> swept_transfers; // If such a spending tx wasn't found in m_transfers, this means the spending tx
// was created by sweep_all, so we can't know the spent height and other detailed info.
std::unordered_map<crypto::key_image, crypto::hash> spent_key_images;
for (const transfer_details &td: m_transfers)
{
for (const cryptonote::txin_v& in : td.m_tx.vin)
{
if (in.type() == typeid(cryptonote::txin_to_key))
spent_key_images.insert(std::make_pair(boost::get<cryptonote::txin_to_key>(in).k_image, td.m_txid));
}
}
for(size_t i = 0; i < signed_key_images.size(); ++i)
{
transfer_details &td = m_transfers[i];
@@ -9585,28 +9608,11 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
if (i < daemon_resp.spent_status.size() && daemon_resp.spent_status[i] == COMMAND_RPC_IS_KEY_IMAGE_SPENT::SPENT_IN_BLOCKCHAIN)
{
bool is_spent_tx_found = false;
for (auto it = m_transfers.rbegin(); &(*it) != &td; ++it)
{
bool is_spent_tx = false;
for(const cryptonote::txin_v& in : it->m_tx.vin)
{
if(in.type() == typeid(cryptonote::txin_to_key) && td.m_key_image == boost::get<cryptonote::txin_to_key>(in).k_image)
{
is_spent_tx = true;
break;
}
}
if (is_spent_tx)
{
is_spent_tx_found = true;
spent_txids.insert(it->m_txid);
break;
}
}
if (!is_spent_tx_found)
const std::unordered_map<crypto::key_image, crypto::hash>::const_iterator skii = spent_key_images.find(td.m_key_image);
if (skii == spent_key_images.end())
swept_transfers.push_back(i);
else
spent_txids.insert(skii->second);
}
}
MDEBUG("Total: " << print_money(spent) << " spent, " << print_money(unspent) << " unspent");
@@ -9729,11 +9735,10 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
{
const transfer_details& td = m_transfers[n];
confirmed_transfer_details pd;
pd.m_change = (uint64_t)-1; // cahnge is unknown
pd.m_change = (uint64_t)-1; // change is unknown
pd.m_amount_in = pd.m_amount_out = td.amount(); // fee is unknown
std::string err;
pd.m_block_height = get_daemon_blockchain_height(err); // spent block height is unknown, so hypothetically set to the highest
crypto::hash spent_txid = crypto::rand<crypto::hash>(); // spent txid is unknown, so hypothetically set to random
pd.m_block_height = 0; // spent block height is unknown
const crypto::hash &spent_txid = crypto::null_hash; // spent txid is unknown
m_confirmed_txs.insert(std::make_pair(spent_txid, pd));
}
}
@@ -9828,18 +9833,20 @@ size_t wallet2::import_outputs(const std::vector<tools::wallet2::transfer_detail
crypto::public_key tx_pub_key = get_tx_pub_key_from_received_outs(td);
const std::vector<crypto::public_key> additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx);
THROW_WALLET_EXCEPTION_IF(td.m_tx.vout[td.m_internal_output_index].target.type() != typeid(cryptonote::txout_to_key),
error::wallet_internal_error, "Unsupported output type");
const crypto::public_key& out_key = boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key;
bool r = cryptonote::generate_key_image_helper(m_account.get_keys(), m_subaddresses, out_key, tx_pub_key, additional_tx_pub_keys, td.m_internal_output_index, in_ephemeral, td.m_key_image, m_account.get_device());
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
td.m_key_image_partial = false;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != boost::get<cryptonote::txout_to_key>(td.m_tx.vout[td.m_internal_output_index].target).key,
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i));
m_key_images[td.m_key_image] = m_transfers.size();
m_pub_keys[td.get_public_key()] = m_transfers.size();
m_transfers.push_back(td);
m_transfers.push_back(std::move(td));
}
return m_transfers.size();

View File

@@ -624,6 +624,7 @@ namespace tools
// Subaddress scheme
cryptonote::account_public_address get_subaddress(const cryptonote::subaddress_index& index) const;
cryptonote::account_public_address get_address() const { return get_subaddress({0,0}); }
boost::optional<cryptonote::subaddress_index> get_subaddress_index(const cryptonote::account_public_address& address) const;
crypto::public_key get_subaddress_spend_public_key(const cryptonote::subaddress_index& index) const;
std::vector<crypto::public_key> get_subaddress_spend_public_keys(uint32_t account, uint32_t begin, uint32_t end) const;
std::string get_subaddress_as_str(const cryptonote::subaddress_index& index) const;
@@ -851,8 +852,8 @@ namespace tools
void set_default_priority(uint32_t p) { m_default_priority = p; }
bool auto_refresh() const { return m_auto_refresh; }
void auto_refresh(bool r) { m_auto_refresh = r; }
bool confirm_missing_payment_id() const { return m_confirm_missing_payment_id; }
void confirm_missing_payment_id(bool always) { m_confirm_missing_payment_id = always; }
bool confirm_subaddress() const { return m_confirm_subaddress; }
void confirm_subaddress(bool always) { m_confirm_subaddress = always; }
bool ask_password() const { return m_ask_password; }
void ask_password(bool always) { m_ask_password = always; }
void set_min_output_count(uint32_t count) { m_min_output_count = count; }
@@ -1196,7 +1197,7 @@ namespace tools
// If m_refresh_from_block_height is explicitly set to zero we need this to differentiate it from the case that
// m_refresh_from_block_height was defaulted to zero.*/
bool m_explicit_refresh_from_block_height;
bool m_confirm_missing_payment_id;
bool m_confirm_subaddress;
bool m_confirm_non_default_ring_size;
bool m_ask_password;
uint32_t m_min_output_count;

View File

@@ -336,14 +336,20 @@ namespace tools
std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(req.account_index);
std::vector<tools::wallet2::transfer_details> transfers;
m_wallet->get_transfers(transfers);
for (const auto& i : balance_per_subaddress)
std::set<uint32_t> address_indices = req.address_indices;
if (address_indices.empty())
{
for (const auto& i : balance_per_subaddress)
address_indices.insert(i.first);
}
for (uint32_t i : address_indices)
{
wallet_rpc::COMMAND_RPC_GET_BALANCE::per_subaddress_info info;
info.address_index = i.first;
info.address_index = i;
cryptonote::subaddress_index index = {req.account_index, info.address_index};
info.address = m_wallet->get_subaddress_as_str(index);
info.balance = i.second;
info.unlocked_balance = unlocked_balance_per_subaddress[i.first];
info.balance = balance_per_subaddress[i];
info.unlocked_balance = unlocked_balance_per_subaddress[i];
info.label = m_wallet->get_subaddress_label(index);
info.num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == index; });
res.per_subaddress.push_back(info);
@@ -397,6 +403,27 @@ namespace tools
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_getaddress_index(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
cryptonote::address_parse_info info;
if(!get_account_address_from_str(info, m_wallet->nettype(), req.address))
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Invalid address";
return false;
}
auto index = m_wallet->get_subaddress_index(info.address);
if (!index)
{
er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS;
er.message = "Address doesn't belong to the wallet";
return false;
}
res.index = *index;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_create_address(const wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::response& res, epee::json_rpc::error& er)
{
if (!m_wallet) return not_open(er);
@@ -1938,8 +1965,8 @@ namespace tools
for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) {
if (i->second.m_tx_hash == txid)
{
fill_transfer_entry(res.transfer, i->second.m_tx_hash, i->first, i->second);
return true;
res.transfers.resize(res.transfers.size() + 1);
fill_transfer_entry(res.transfers.back(), i->second.m_tx_hash, i->first, i->second);
}
}
@@ -1948,8 +1975,8 @@ namespace tools
for (std::list<std::pair<crypto::hash, tools::wallet2::confirmed_transfer_details>>::const_iterator i = payments_out.begin(); i != payments_out.end(); ++i) {
if (i->first == txid)
{
fill_transfer_entry(res.transfer, i->first, i->second);
return true;
res.transfers.resize(res.transfers.size() + 1);
fill_transfer_entry(res.transfers.back(), i->first, i->second);
}
}
@@ -1958,8 +1985,8 @@ namespace tools
for (std::list<std::pair<crypto::hash, tools::wallet2::unconfirmed_transfer_details>>::const_iterator i = upayments.begin(); i != upayments.end(); ++i) {
if (i->first == txid)
{
fill_transfer_entry(res.transfer, i->first, i->second);
return true;
res.transfers.resize(res.transfers.size() + 1);
fill_transfer_entry(res.transfers.back(), i->first, i->second);
}
}
@@ -1970,11 +1997,17 @@ namespace tools
for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) {
if (i->second.m_pd.m_tx_hash == txid)
{
fill_transfer_entry(res.transfer, i->first, i->second);
return true;
res.transfers.resize(res.transfers.size() + 1);
fill_transfer_entry(res.transfers.back(), i->first, i->second);
}
}
if (!res.transfers.empty())
{
res.transfer = res.transfers.front(); // backward compat
return true;
}
er.code = WALLET_RPC_ERROR_CODE_WRONG_TXID;
er.message = "Transaction not found.";
return false;
@@ -3007,6 +3040,7 @@ just_dir:
wrpc.send_stop_signal();
});
LOG_PRINT_L0(tools::wallet_rpc_server::tr("Starting wallet RPC server"));
LOG_PRINT_L0(tools::wallet_rpc_server::tr("WARNING: Payment IDs/integrated addresses will be deprecated soon. Use sub-addresses."));
try
{
wrpc.run();

View File

@@ -69,6 +69,7 @@ namespace tools
BEGIN_JSON_RPC_MAP("/json_rpc")
MAP_JON_RPC_WE("get_balance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("get_address", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("get_address_index", on_getaddress_index, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX)
MAP_JON_RPC_WE("getbalance", on_getbalance, wallet_rpc::COMMAND_RPC_GET_BALANCE)
MAP_JON_RPC_WE("getaddress", on_getaddress, wallet_rpc::COMMAND_RPC_GET_ADDRESS)
MAP_JON_RPC_WE("create_address", on_create_address, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS)
@@ -141,6 +142,7 @@ namespace tools
//json_rpc
bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er);
bool on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er);
bool on_getaddress_index(const wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS_INDEX::response& res, epee::json_rpc::error& er);
bool on_create_address(const wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_CREATE_ADDRESS::response& res, epee::json_rpc::error& er);
bool on_label_address(const wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_LABEL_ADDRESS::response& res, epee::json_rpc::error& er);
bool on_get_accounts(const wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::request& req, wallet_rpc::COMMAND_RPC_GET_ACCOUNTS::response& res, epee::json_rpc::error& er);

View File

@@ -39,6 +39,17 @@
#undef MONERO_DEFAULT_LOG_CATEGORY
#define MONERO_DEFAULT_LOG_CATEGORY "wallet.rpc"
// When making *any* change here, bump minor
// If the change is incompatible, then bump major and set minor to 0
// This ensures WALLET_RPC_VERSION always increases, that every change
// has its own version, and that clients can just test major to see
// whether they can talk to a given wallet without having to know in
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define WALLET_RPC_VERSION_MAJOR 1
#define WALLET_RPC_VERSION_MINOR 4
#define MAKE_WALLET_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define WALLET_RPC_VERSION MAKE_WALLET_RPC_VERSION(WALLET_RPC_VERSION_MAJOR, WALLET_RPC_VERSION_MINOR)
namespace tools
{
namespace wallet_rpc
@@ -51,8 +62,10 @@ namespace wallet_rpc
struct request
{
uint32_t account_index;
std::set<uint32_t> address_indices;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(account_index)
KV_SERIALIZE(address_indices)
END_KV_SERIALIZE_MAP()
};
@@ -130,6 +143,25 @@ namespace wallet_rpc
};
};
struct COMMAND_RPC_GET_ADDRESS_INDEX
{
struct request
{
std::string address;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(address)
END_KV_SERIALIZE_MAP()
};
struct response
{
cryptonote::subaddress_index index;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(index)
END_KV_SERIALIZE_MAP()
};
};
struct COMMAND_RPC_CREATE_ADDRESS
{
struct request
@@ -1311,9 +1343,11 @@ namespace wallet_rpc
struct response
{
transfer_entry transfer;
std::list<transfer_entry> transfers;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(transfer);
KV_SERIALIZE(transfers);
END_KV_SERIALIZE_MAP()
};
};