diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 14 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_boost_serialization.h | 8 | ||||
-rw-r--r-- | src/ringct/rctOps.cpp | 15 | ||||
-rw-r--r-- | src/ringct/rctOps.h | 3 | ||||
-rw-r--r-- | src/ringct/rctSigs.cpp | 163 | ||||
-rw-r--r-- | src/ringct/rctSigs.h | 17 | ||||
-rw-r--r-- | src/ringct/rctTypes.h | 22 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 43 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 128 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.cpp | 41 | ||||
-rw-r--r-- | src/wallet/wallet_rpc_server.h | 3 |
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; }; } |