aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cryptonote_core/blockchain.cpp14
-rw-r--r--src/cryptonote_core/cryptonote_boost_serialization.h8
-rw-r--r--src/ringct/rctOps.cpp15
-rw-r--r--src/ringct/rctOps.h3
-rw-r--r--src/ringct/rctSigs.cpp163
-rw-r--r--src/ringct/rctSigs.h17
-rw-r--r--src/ringct/rctTypes.h22
-rw-r--r--src/simplewallet/simplewallet.cpp43
-rw-r--r--src/wallet/wallet2.cpp128
-rw-r--r--src/wallet/wallet_rpc_server.cpp41
-rw-r--r--src/wallet/wallet_rpc_server.h3
11 files changed, 246 insertions, 211 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index df9c0f3f3..efda3f5cf 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -91,8 +91,8 @@ static const struct {
// version 3 starts from block 1141317, which is on or around the 24th of September, 2016. Fork time finalised on 2016-03-21.
{ 3, 1141317, 0, 1458558528 },
- // version 4 starts from block 1220517, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18.
- { 4, 1220517, 0, 1483574400 },
+ // version 4 starts from block 1220516, which is on or around the 5th of January, 2017. Fork time finalised on 2016-09-18.
+ { 4, 1220516, 0, 1483574400 },
// version 5 starts from block 1406997, which is on or around the 20th of September, 2017. Fork time finalised on 2016-09-18.
{ 5, 1406997, 0, 1505865600 },
@@ -113,7 +113,7 @@ static const struct {
// versions 3-5 were passed in rapid succession from September 18th, 2016
{ 3, 800500, 0, 1472415034 },
- { 4, 801220, 0, 1472415035 },
+ { 4, 801219, 0, 1472415035 },
{ 5, 802660, 0, 1472415036 },
};
static const uint64_t testnet_hard_fork_version_1_till = 624633;
@@ -832,12 +832,12 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash::
// looking into.
add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl));
LOG_PRINT_L1("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl));
- m_alternative_chains.erase(ch_ent);
+ m_alternative_chains.erase(*alt_ch_iter++);
- for(auto alt_ch_to_orph_iter = ++alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); alt_ch_to_orph_iter++)
+ for(auto alt_ch_to_orph_iter = alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); )
{
- add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first);
- m_alternative_chains.erase(*alt_ch_to_orph_iter);
+ add_block_as_invalid((*alt_ch_to_orph_iter)->second, (*alt_ch_to_orph_iter)->first);
+ m_alternative_chains.erase(*alt_ch_to_orph_iter++);
}
return false;
}
diff --git a/src/cryptonote_core/cryptonote_boost_serialization.h b/src/cryptonote_core/cryptonote_boost_serialization.h
index 19b1a687e..663ef5070 100644
--- a/src/cryptonote_core/cryptonote_boost_serialization.h
+++ b/src/cryptonote_core/cryptonote_boost_serialization.h
@@ -207,11 +207,11 @@ namespace boost
}
template <class Archive>
- inline void serialize(Archive &a, rct::asnlSig &x, const boost::serialization::version_type ver)
+ inline void serialize(Archive &a, rct::boroSig &x, const boost::serialization::version_type ver)
{
- a & x.L1;
- a & x.s2;
- a & x.s;
+ a & x.s0;
+ a & x.s1;
+ a & x.ee;
}
template <class Archive>
diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp
index cf55897a7..21f29ccf5 100644
--- a/src/ringct/rctOps.cpp
+++ b/src/ringct/rctOps.cpp
@@ -267,7 +267,7 @@ namespace rct {
ge_p3_tobytes(AB.bytes, &A2);
}
- //checks if A, B are equal as curve points
+ //checks if A, B are equal in terms of bytes (may say no if one is a non-reduced scalar)
//without doing curve operations
bool equalKeys(const key & a, const key & b) {
bool rv = true;
@@ -359,6 +359,19 @@ namespace rct {
return rv;
}
+ key cn_fast_hash(const key64 keys) {
+ key rv;
+ cn_fast_hash(rv, &keys[0], 64 * sizeof(keys[0]));
+ //dp(rv);
+ return rv;
+ }
+
+ key hash_to_scalar(const key64 keys) {
+ key rv = cn_fast_hash(keys);
+ sc_reduce32(rv.bytes);
+ return rv;
+ }
+
key hashToPointSimple(const key & hh) {
key pointk;
ge_p1p1 point2;
diff --git a/src/ringct/rctOps.h b/src/ringct/rctOps.h
index cd3a6dc0d..90f54b050 100644
--- a/src/ringct/rctOps.h
+++ b/src/ringct/rctOps.h
@@ -158,6 +158,9 @@ namespace rct {
//for mg sigs
key cn_fast_hash(const keyV &keys);
key hash_to_scalar(const keyV &keys);
+ //for ANSL
+ key cn_fast_hash(const key64 keys);
+ key hash_to_scalar(const key64 keys);
//returns hashToPoint as described in https://github.com/ShenNoether/ge_fromfe_writeup
key hashToPointSimple(const key &in);
diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp
index b773be1e5..b7efe3ae7 100644
--- a/src/ringct/rctSigs.cpp
+++ b/src/ringct/rctSigs.cpp
@@ -40,94 +40,66 @@ using namespace crypto;
using namespace std;
namespace rct {
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
-
- void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index) {
- key c1, c2, L2;
- key a = skGen();
- if (index == 0) {
- scalarmultBase(L1, a);
- hash_to_scalar(c2, L1);
- skGen(s2);
- addKeys2(L2, s2, c2, P2);
- hash_to_scalar(c1, L2);
- //s1 = a - x * c1
- sc_mulsub(s1.bytes, x.bytes, c1.bytes, a.bytes);
- }
- else if (index == 1) {
- scalarmultBase(L2, a);
- hash_to_scalar(c1, L2);
- skGen(s1);
- addKeys2(L1, s1, c1, P1);
- hash_to_scalar(c2, L1);
- sc_mulsub(s2.bytes, x.bytes, c2.bytes, a.bytes);
- }
- else {
- throw std::runtime_error("GenSchnorrNonLinkable: invalid index (should be 0 or 1)");
+ namespace {
+ struct verRangeWrapper_ {
+ void operator()(const key & C, const rangeSig & as, bool &result) const {
+ result = verRange(C, as);
}
- }
+ };
+ constexpr const verRangeWrapper_ verRangeWrapper{};
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
- bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2) {
- key c2, L2, c1, L1p;
- hash_to_scalar(c2, L1);
- addKeys2(L2, s2, c2, P2);
- hash_to_scalar(c1, L2);
- addKeys2(L1p, s1, c1, P1);
-
- return equalKeys(L1, L1p);
+ struct verRctMGSimpleWrapper_ {
+ void operator()(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C, bool &result) const {
+ result = verRctMGSimple(message, mg, pubs, C);
+ }
+ };
+ constexpr const verRctMGSimpleWrapper_ verRctMGSimpleWrapper{};
}
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices) {
- DP("Generating Aggregate Schnorr Non-linkable Ring Signature\n");
- key64 s1;
- int j = 0;
- asnlSig rv;
- rv.s = zero();
- for (j = 0; j < ATOMS; j++) {
- GenSchnorrNonLinkable(rv.L1[j], s1[j], rv.s2[j], x[j], P1[j], P2[j], indices[j]);
- sc_add(rv.s.bytes, rv.s.bytes, s1[j].bytes);
+ //Borromean (c.f. gmax/andytoshi's paper)
+ boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices) {
+ key64 L[2], alpha;
+ key c;
+ int naught = 0, prime = 0, ii = 0, jj=0;
+ boroSig bb;
+ for (ii = 0 ; ii < 64 ; ii++) {
+ naught = indices[ii]; prime = (indices[ii] + 1) % 2;
+ skGen(alpha[ii]);
+ scalarmultBase(L[naught][ii], alpha[ii]);
+ if (naught == 0) {
+ skGen(bb.s1[ii]);
+ c = hash_to_scalar(L[naught][ii]);
+ addKeys2(L[prime][ii], bb.s1[ii], c, P2[ii]);
+ }
}
- return rv;
- }
-
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as) {
- PERF_TIMER(VerASNL);
- DP("Verifying Aggregate Schnorr Non-linkable Ring Signature\n");
- key LHS = identity();
- key RHS = scalarmultBase(as.s);
- key c2, L2, c1;
- int j = 0;
- for (j = 0; j < ATOMS; j++) {
- hash_to_scalar(c2, as.L1[j]);
- addKeys2(L2, as.s2[j], c2, P2[j]);
- addKeys(LHS, LHS, as.L1[j]);
- hash_to_scalar(c1, L2);
- addKeys(RHS, RHS, scalarmultKey(P1[j], c1));
- }
- key cc;
- sc_sub(cc.bytes, LHS.bytes, RHS.bytes);
- return sc_isnonzero(cc.bytes) == 0;
+ bb.ee = hash_to_scalar(L[1]); //or L[1]..
+ key LL, cc;
+ for (jj = 0 ; jj < 64 ; jj++) {
+ if (!indices[jj]) {
+ sc_mulsub(bb.s0[jj].bytes, x[jj].bytes, bb.ee.bytes, alpha[jj].bytes);
+ } else {
+ skGen(bb.s0[jj]);
+ addKeys2(LL, bb.s0[jj], bb.ee, P1[jj]); //different L0
+ cc = hash_to_scalar(LL);
+ sc_mulsub(bb.s1[jj].bytes, x[jj].bytes, cc.bytes, alpha[jj].bytes);
+ }
+ }
+ return bb;
}
+ //see above.
+ bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2) {
+ key64 Lv1; key chash, LL;
+ int ii = 0;
+ for (ii = 0 ; ii < 64 ; ii++) {
+ addKeys2(LL, bb.s0[ii], bb.ee, P1[ii]);
+ chash = hash_to_scalar(LL);
+ addKeys2(Lv1[ii], bb.s1[ii], chash, P2[ii]);
+ }
+ key eeComputed = hash_to_scalar(Lv1); //hash function fine
+ return equalKeys(eeComputed, bb.ee);
+ }
+
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. http://eprint.iacr.org/2015/1098 section 2.
@@ -259,6 +231,11 @@ namespace rct {
}
CHECK_AND_ASSERT_MES(dsRows <= rows, false, "Bad dsRows value");
+ for (size_t i = 0; i < rv.ss.size(); ++i)
+ for (size_t j = 0; j < rv.ss[i].size(); ++j)
+ CHECK_AND_ASSERT_MES(sc_check(rv.ss[i][j].bytes) == 0, false, "Bad ss slot");
+ CHECK_AND_ASSERT_MES(sc_check(rv.cc.bytes) == 0, false, "Bad cc");
+
size_t i = 0, j = 0, ii = 0;
key c, L, R, Hi;
key c_old = copy(rv.cc);
@@ -323,7 +300,7 @@ namespace rct {
sc_add(mask.bytes, mask.bytes, ai[i].bytes);
addKeys(C, C, sig.Ci[i]);
}
- sig.asig = GenASNL(ai, sig.Ci, CiH, b);
+ sig.asig = genBorromean(ai, sig.Ci, CiH, b);
return sig;
}
@@ -335,6 +312,8 @@ namespace rct {
// mask is a such that C = aG + bH, and b = amount
//verRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
bool verRange(const key & C, const rangeSig & as) {
+ try
+ {
PERF_TIMER(verRange);
key64 CiH;
int i = 0;
@@ -345,9 +324,12 @@ namespace rct {
}
if (!equalKeys(C, Ctmp))
return false;
- if (!VerASNL(as.Ci, CiH, as.asig))
+ if (!verifyBorromean(as.asig, as.Ci, CiH))
return false;
return true;
+ }
+ // we can get deep throws from ge_frombytes_vartime if input isn't valid
+ catch (...) { return false; }
}
key get_pre_mlsag_hash(const rctSig &rv)
@@ -371,10 +353,10 @@ namespace rct {
for (auto r: rv.p.rangeSigs)
{
for (size_t n = 0; n < 64; ++n)
- kv.push_back(r.asig.L1[n]);
+ kv.push_back(r.asig.s0[n]);
for (size_t n = 0; n < 64; ++n)
- kv.push_back(r.asig.s2[n]);
- kv.push_back(r.asig.s);
+ kv.push_back(r.asig.s1[n]);
+ kv.push_back(r.asig.ee);
for (size_t n = 0; n < 64; ++n)
kv.push_back(r.Ci[n]);
}
@@ -513,6 +495,8 @@ namespace rct {
//This does a simplified version, assuming only post Rct
//inputs
bool verRctMGSimple(const key &message, const mgSig &mg, const ctkeyV & pubs, const key & C) {
+ try
+ {
PERF_TIMER(verRctMGSimple);
//setup vars
size_t rows = 1;
@@ -528,6 +512,8 @@ namespace rct {
}
//DP(C);
return MLSAG_Ver(message, M, mg, rows);
+ }
+ catch (...) { return false; }
}
@@ -790,6 +776,8 @@ namespace rct {
//ver RingCT simple
//assumes only post-rct style inputs (at least for max anonymity)
bool verRctSimple(const rctSig & rv) {
+ try
+ {
PERF_TIMER(verRctSimple);
CHECK_AND_ASSERT_MES(rv.type == RCTTypeSimple, false, "verRctSimple called on non simple rctSig");
@@ -860,6 +848,9 @@ namespace rct {
}
return true;
+ }
+ // we can get deep throws from ge_frombytes_vartime if input isn't valid
+ catch (...) { return false; }
}
//RingCT protocol
diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h
index a4fecade4..1fe4aa074 100644
--- a/src/ringct/rctSigs.h
+++ b/src/ringct/rctSigs.h
@@ -66,21 +66,8 @@ using namespace crypto;
namespace rct {
- //Schnorr Non-linkable
- //Gen Gives a signature (L1, s1, s2) proving that the sender knows "x" such that xG = one of P1 or P2
- //Ver Verifies that signer knows an "x" such that xG = one of P1 or P2
- //These are called in the below ASNL sig generation
- void GenSchnorrNonLinkable(key & L1, key & s1, key & s2, const key & x, const key & P1, const key & P2, unsigned int index);
- bool VerSchnorrNonLinkable(const key & P1, const key & P2, const key & L1, const key & s1, const key & s2);
-
- //Aggregate Schnorr Non-linkable Ring Signature (ASNL)
- // c.f. http://eprint.iacr.org/2015/1098 section 5.
- // These are used in range proofs (alternatively Borromean could be used)
- // Gen gives a signature which proves the signer knows, for each i,
- // an x[i] such that x[i]G = one of P1[i] or P2[i]
- // Ver Verifies the signer knows a key for one of P1[i], P2[i] at each i
- asnlSig GenASNL(key64 x, key64 P1, key64 P2, bits indices);
- bool VerASNL(const key64 P1, const key64 P2, const asnlSig &as);
+ boroSig genBorromean(const key64 x, const key64 P1, const key64 P2, const bits indices);
+ bool verifyBorromean(const boroSig &bb, const key64 P1, const key64 P2);
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//These are aka MG signatutes in earlier drafts of the ring ct paper
diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h
index b1921b71a..71cc61ddc 100644
--- a/src/ringct/rctTypes.h
+++ b/src/ringct/rctTypes.h
@@ -125,12 +125,10 @@ namespace rct {
typedef unsigned int bits[ATOMS];
typedef key key64[64];
- //just contains the necessary keys to represent asnlSigs
- //c.f. http://eprint.iacr.org/2015/1098
- struct asnlSig {
- key64 L1;
- key64 s2;
- key s;
+ struct boroSig {
+ key64 s0;
+ key64 s1;
+ key ee;
};
//Container for precomp
@@ -151,14 +149,14 @@ namespace rct {
// FIELD(II) - not serialized, it can be reconstructed
END_SERIALIZE()
};
- //contains the data for an asnl sig
+ //contains the data for an Borromean sig
// also contains the "Ci" values such that
// \sum Ci = C
// and the signature proves that each Ci is either
// a Pedersen commitment to 0 or to 2^i
//thus proving that C is in the range of [0, 2^64]
struct rangeSig {
- asnlSig asig;
+ boroSig asig;
key64 Ci;
BEGIN_SERIALIZE_OBJECT()
@@ -452,7 +450,7 @@ inline std::ostream &operator <<(std::ostream &o, const rct::key &v) { return pr
BLOB_SERIALIZER(rct::key);
BLOB_SERIALIZER(rct::key64);
BLOB_SERIALIZER(rct::ctkey);
-BLOB_SERIALIZER(rct::asnlSig);
+BLOB_SERIALIZER(rct::boroSig);
VARIANT_TAG(debug_archive, rct::key, "rct::key");
VARIANT_TAG(debug_archive, rct::key64, "rct::key64");
@@ -464,7 +462,7 @@ VARIANT_TAG(debug_archive, rct::ctkeyM, "rct::ctkeyM");
VARIANT_TAG(debug_archive, rct::ecdhTuple, "rct::ecdhTuple");
VARIANT_TAG(debug_archive, rct::mgSig, "rct::mgSig");
VARIANT_TAG(debug_archive, rct::rangeSig, "rct::rangeSig");
-VARIANT_TAG(debug_archive, rct::asnlSig, "rct::asnlSig");
+VARIANT_TAG(debug_archive, rct::boroSig, "rct::boroSig");
VARIANT_TAG(debug_archive, rct::rctSig, "rct::rctSig");
VARIANT_TAG(binary_archive, rct::key, 0x90);
@@ -477,7 +475,7 @@ VARIANT_TAG(binary_archive, rct::ctkeyM, 0x96);
VARIANT_TAG(binary_archive, rct::ecdhTuple, 0x97);
VARIANT_TAG(binary_archive, rct::mgSig, 0x98);
VARIANT_TAG(binary_archive, rct::rangeSig, 0x99);
-VARIANT_TAG(binary_archive, rct::asnlSig, 0x9a);
+VARIANT_TAG(binary_archive, rct::boroSig, 0x9a);
VARIANT_TAG(binary_archive, rct::rctSig, 0x9b);
VARIANT_TAG(json_archive, rct::key, "rct_key");
@@ -490,7 +488,7 @@ VARIANT_TAG(json_archive, rct::ctkeyM, "rct_ctkeyM");
VARIANT_TAG(json_archive, rct::ecdhTuple, "rct_ecdhTuple");
VARIANT_TAG(json_archive, rct::mgSig, "rct_mgSig");
VARIANT_TAG(json_archive, rct::rangeSig, "rct_rangeSig");
-VARIANT_TAG(json_archive, rct::asnlSig, "rct_asnlSig");
+VARIANT_TAG(json_archive, rct::boroSig, "rct_boroSig");
VARIANT_TAG(json_archive, rct::rctSig, "rct_rctSig");
#endif /* RCTTYPES_H */
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index faeed31ce..d9c1bb4ed 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -949,6 +949,37 @@ void simple_wallet::print_seed(std::string seed)
std::cout << seed << std::endl;
}
//----------------------------------------------------------------------------------------------------
+static bool is_local_daemon(const std::string &address)
+{
+ // extract host
+ epee::net_utils::http::url_content u_c;
+ if (!epee::net_utils::parse_url(address, u_c))
+ {
+ LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
+ return false;
+ }
+ if (u_c.host.empty())
+ {
+ LOG_PRINT_L1("Failed to determine whether daemon is local, assuming not");
+ return false;
+ }
+
+ // resolve to IP
+ boost::asio::io_service io_service;
+ boost::asio::ip::tcp::resolver resolver(io_service);
+ boost::asio::ip::tcp::resolver::query query(u_c.host, "");
+ boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query);
+ while (i != boost::asio::ip::tcp::resolver::iterator())
+ {
+ const boost::asio::ip::tcp::endpoint &ep = *i;
+ if (ep.address().is_loopback())
+ return true;
+ ++i;
+ }
+
+ return false;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
if (!handle_command_line(vm))
@@ -1158,6 +1189,18 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
CHECK_AND_ASSERT_MES(r, false, tr("failed to open account"));
}
assert(m_wallet);
+
+ // set --trusted-daemon if local
+ try
+ {
+ if (is_local_daemon(m_wallet->get_daemon_address()))
+ {
+ LOG_PRINT_L1(tr("Daemon is local, assuming trusted"));
+ m_trusted_daemon = true;
+ }
+ }
+ catch (const std::exception &e) { }
+
m_wallet->callback(this);
return true;
}
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index fee1a0ab7..c30a0949c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1575,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
@@ -1613,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;
}
}
}
@@ -3775,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/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;
};
}