diff options
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | src/common/dns_utils.cpp | 45 | ||||
-rw-r--r-- | src/common/dns_utils.h | 2 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.cpp | 27 | ||||
-rw-r--r-- | src/cryptonote_core/blockchain.h | 7 | ||||
-rw-r--r-- | src/cryptonote_core/cryptonote_core.cpp | 3 | ||||
-rw-r--r-- | src/mnemonics/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/mnemonics/electrum-words.cpp | 9 | ||||
-rw-r--r-- | src/mnemonics/lojban.h | 1693 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 28 | ||||
-rw-r--r-- | src/wallet/wallet2.cpp | 131 | ||||
-rw-r--r-- | src/wallet/wallet2.h | 4 | ||||
-rw-r--r-- | tests/unit_tests/dns_resolver.cpp | 14 | ||||
-rw-r--r-- | tests/unit_tests/mnemonics.cpp | 4 | ||||
-rw-r--r-- | utils/gpg_keys/mishi_choudhary.asc | 125 |
15 files changed, 2050 insertions, 49 deletions
@@ -123,7 +123,7 @@ Installing a snap is very quick. Snaps are secure. They are isolated with all of * Arch Linux (via [AUR](https://aur.archlinux.org/)): - Stable release: [`monero`](https://aur.archlinux.org/packages/monero) - - Bleeding edge: [`bitmonero-git`](https://aur.archlinux.org/packages/bitmonero-git) + - Bleeding edge: [`monero-git`](https://aur.archlinux.org/packages/monero-git) * OS X via [Homebrew](http://brew.sh) @@ -414,7 +414,7 @@ See [README.i18n.md](README.i18n.md). ## Using Tor -While Monero isn't made to integrate with Tor, it can be used wrapped with torsocks, if you add --p2p-bind-ip 127.0.0.1 to the monerod command line. You also want to set DNS requests to go over TCP, so they'll be routed through Tor, by setting DNS_PUBLIC=tcp. You may also disable IGD (UPnP port forwarding negotiation), which is pointless with Tor. To allow local connections from the wallet, you might have to add TORSOCKS_ALLOW_INBOUND=1, some OSes need it and some don't. Example: +While Monero isn't made to integrate with Tor, it can be used wrapped with torsocks, if you add --p2p-bind-ip 127.0.0.1 to the monerod command line. You also want to set DNS requests to go over TCP, so they'll be routed through Tor, by setting DNS_PUBLIC=tcp or use a particular DNS server with DNS_PUBLIC=tcp://a.b.c.d (default is 8.8.4.4, which is Google DNS). You may also disable IGD (UPnP port forwarding negotiation), which is pointless with Tor. To allow local connections from the wallet, you might have to add TORSOCKS_ALLOW_INBOUND=1, some OSes need it and some don't. Example: `DNS_PUBLIC=tcp torsocks monerod --p2p-bind-ip 127.0.0.1 --no-igd` diff --git a/src/common/dns_utils.cpp b/src/common/dns_utils.cpp index 1310b8bfd..f549218cb 100644 --- a/src/common/dns_utils.cpp +++ b/src/common/dns_utils.cpp @@ -40,6 +40,8 @@ namespace bf = boost::filesystem; #undef MONERO_DEFAULT_LOG_CATEGORY #define MONERO_DEFAULT_LOG_CATEGORY "net.dns" +#define DEFAULT_DNS_PUBLIC_ADDR "8.8.4.4" + static boost::mutex instance_lock; namespace @@ -197,16 +199,19 @@ public: DNSResolver::DNSResolver() : m_data(new DNSResolverData()) { int use_dns_public = 0; - const char* dns_public_addr = "8.8.4.4"; + std::string dns_public_addr = DEFAULT_DNS_PUBLIC_ADDR; if (auto res = getenv("DNS_PUBLIC")) { - std::string dns_public(res); - // TODO: could allow parsing of IP and protocol: e.g. DNS_PUBLIC=tcp:8.8.8.8 - if (dns_public == "tcp") + dns_public_addr = tools::dns_utils::parse_dns_public(res); + if (!dns_public_addr.empty()) { - LOG_PRINT_L0("Using public DNS server: " << dns_public_addr << " (TCP)"); + MGINFO("Using public DNS server: " << dns_public_addr << " (TCP)"); use_dns_public = 1; } + else + { + MERROR("Failed to parse DNS_PUBLIC"); + } } // init libunbound context @@ -214,7 +219,7 @@ DNSResolver::DNSResolver() : m_data(new DNSResolverData()) if (use_dns_public) { - ub_ctx_set_fwd(m_data->m_ub_context, string_copy(dns_public_addr)); + ub_ctx_set_fwd(m_data->m_ub_context, dns_public_addr.c_str()); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-udp:"), string_copy("no")); ub_ctx_set_option(m_data->m_ub_context, string_copy("do-tcp:"), string_copy("yes")); } @@ -519,6 +524,34 @@ bool load_txt_records_from_dns(std::vector<std::string> &good_records, const std return true; } +std::string parse_dns_public(const char *s) +{ + unsigned ip0, ip1, ip2, ip3; + char c; + std::string dns_public_addr; + if (!strcmp(s, "tcp")) + { + dns_public_addr = DEFAULT_DNS_PUBLIC_ADDR; + LOG_PRINT_L0("Using default public DNS server: " << dns_public_addr << " (TCP)"); + } + else if (sscanf(s, "tcp://%u.%u.%u.%u%c", &ip0, &ip1, &ip2, &ip3, &c) == 4) + { + if (ip0 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255) + { + MERROR("Invalid IP: " << s << ", using default"); + } + else + { + dns_public_addr = std::string(s + strlen("tcp://")); + } + } + else + { + MERROR("Invalid DNS_PUBLIC contents, ignored"); + } + return dns_public_addr; +} + } // namespace tools::dns_utils } // namespace tools diff --git a/src/common/dns_utils.h b/src/common/dns_utils.h index f19584516..c0a2dbf2b 100644 --- a/src/common/dns_utils.h +++ b/src/common/dns_utils.h @@ -167,6 +167,8 @@ std::string get_account_address_as_str_from_url(const std::string& url, bool& dn bool load_txt_records_from_dns(std::vector<std::string> &records, const std::vector<std::string> &dns_urls); +std::string parse_dns_public(const char *s); + } // namespace tools::dns_utils } // namespace tools diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 5e0dd33e6..3028866c4 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -2292,6 +2292,24 @@ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<u return true; } //------------------------------------------------------------------ +void Blockchain::on_new_tx_from_block(const cryptonote::transaction &tx) +{ +#if defined(PER_BLOCK_CHECKPOINT) + // check if we're doing per-block checkpointing + if (m_db->height() < m_blocks_hash_check.size()) + { + TIME_MEASURE_START(a); + m_blocks_txs_check.push_back(get_transaction_hash(tx)); + TIME_MEASURE_FINISH(a); + if(m_show_time_stats) + { + size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0; + MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a); + } + } +#endif +} +//------------------------------------------------------------------ //FIXME: it seems this function is meant to be merely a wrapper around // another function of the same name, this one adding one bit of // functionality. Should probably move anything more than that @@ -2307,19 +2325,10 @@ bool Blockchain::check_tx_inputs(transaction& tx, uint64_t& max_used_block_heigh #if defined(PER_BLOCK_CHECKPOINT) // check if we're doing per-block checkpointing - // FIXME: investigate why this block returns if (m_db->height() < m_blocks_hash_check.size() && kept_by_block) { - TIME_MEASURE_START(a); - m_blocks_txs_check.push_back(get_transaction_hash(tx)); max_used_block_id = null_hash; max_used_block_height = 0; - TIME_MEASURE_FINISH(a); - if(m_show_time_stats) - { - size_t ring_size = tx.vin[0].type() == typeid(txin_to_key) ? boost::get<txin_to_key>(tx.vin[0]).key_offsets.size() : 0; - MINFO("HASH: " << "-" << " I/M/O: " << tx.vin.size() << "/" << ring_size << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a); - } return true; } #endif diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index d5bcad2e2..f64bd35e3 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -962,6 +962,13 @@ namespace cryptonote void cancel(); + /** + * @brief called when we see a tx originating from a block + * + * Used for handling txes from historical blocks in a fast way + */ + void on_new_tx_from_block(const cryptonote::transaction &tx); + private: // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index bd01bc69a..cec3f7225 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -899,6 +899,9 @@ namespace cryptonote //----------------------------------------------------------------------------------------------- bool core::add_new_tx(transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block, bool relayed, bool do_not_relay) { + if (keeped_by_block) + get_blockchain_storage().on_new_tx_from_block(tx); + if(m_mempool.have_tx(tx_hash)) { LOG_PRINT_L2("tx " << tx_hash << "already have transaction in tx_pool"); diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt index 942b6eca3..5ce2198ae 100644 --- a/src/mnemonics/CMakeLists.txt +++ b/src/mnemonics/CMakeLists.txt @@ -46,7 +46,8 @@ set(mnemonics_private_headers russian.h singleton.h spanish.h - esperanto.h) + esperanto.h + lojban.h) monero_private_headers(mnemonics ${mnemonics_private_headers}) diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp index 2fe5d9985..6ae33a743 100644 --- a/src/mnemonics/electrum-words.cpp +++ b/src/mnemonics/electrum-words.cpp @@ -62,6 +62,7 @@ #include "japanese.h" #include "russian.h" #include "esperanto.h" +#include "lojban.h" #include "english_old.h" #include "language_base.h" #include "singleton.h" @@ -97,6 +98,7 @@ namespace Language::Singleton<Language::Japanese>::instance(), Language::Singleton<Language::Russian>::instance(), Language::Singleton<Language::Esperanto>::instance(), + Language::Singleton<Language::Lojban>::instance(), Language::Singleton<Language::EnglishOld>::instance() }); Language::Base *fallback = NULL; @@ -360,6 +362,10 @@ namespace crypto { language = Language::Singleton<Language::Esperanto>::instance(); } + else if (language_name == "Lojban") + { + language = Language::Singleton<Language::Lojban>::instance(); + } else { return false; @@ -415,7 +421,8 @@ namespace crypto Language::Singleton<Language::Russian>::instance(), Language::Singleton<Language::Japanese>::instance(), Language::Singleton<Language::Chinese_Simplified>::instance(), - Language::Singleton<Language::Esperanto>::instance() + Language::Singleton<Language::Esperanto>::instance(), + Language::Singleton<Language::Lojban>::instance() }); for (std::vector<Language::Base*>::iterator it = language_instances.begin(); it != language_instances.end(); it++) diff --git a/src/mnemonics/lojban.h b/src/mnemonics/lojban.h new file mode 100644 index 000000000..8ea9510a3 --- /dev/null +++ b/src/mnemonics/lojban.h @@ -0,0 +1,1693 @@ +// Copyright (c) 2014-2017, The Monero Project
+//
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification, are
+// permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this list of
+// conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice, this list
+// of conditions and the following disclaimer in the documentation and/or other
+// materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors may be
+// used to endorse or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+/*!
+ * \file lojban.h
+ *
+ * \brief New Lojban word list and map.
+ */
+
+/*
+ * Word list authored by: sorpaas
+ * Sources:
+ * lo gimste jo'u lo ma'oste (http://guskant.github.io/lojbo/gismu-cmavo.html)
+ * N-grams of Lojban corpus (https://mw.lojban.org/papri/N-grams_of_Lojban_corpus)
+ */
+
+#ifndef LOJBAN_H
+#define LOJBAN_H
+
+#include <vector>
+#include <unordered_map>
+#include "language_base.h"
+#include <string>
+
+/*!
+ * \namespace Language
+ * \brief Mnemonic language related namespace.
+ */
+namespace Language
+{
+ class Lojban: public Base
+ {
+ public:
+ Lojban(): Base("Lojban", std::vector<std::string>({
+ "backi",
+ "bacru",
+ "badna",
+ "badri",
+ "bajra",
+ "bakfu",
+ "bakni",
+ "bakri",
+ "baktu",
+ "balji",
+ "balni",
+ "balre",
+ "balvi",
+ "bambu",
+ "bancu",
+ "bandu",
+ "banfi",
+ "bangu",
+ "banli",
+ "banro",
+ "banxa",
+ "banzu",
+ "bapli",
+ "barda",
+ "bargu",
+ "barja",
+ "barna",
+ "bartu",
+ "basfa",
+ "basna",
+ "basti",
+ "batci",
+ "batke",
+ "bavmi",
+ "baxso",
+ "bebna",
+ "bekpi",
+ "bemro",
+ "bende",
+ "bengo",
+ "benji",
+ "benre",
+ "benzo",
+ "bergu",
+ "bersa",
+ "berti",
+ "besna",
+ "besto",
+ "betfu",
+ "betri",
+ "bevri",
+ "bidju",
+ "bifce",
+ "bikla",
+ "bilga",
+ "bilma",
+ "bilni",
+ "bindo",
+ "binra",
+ "binxo",
+ "birje",
+ "birka",
+ "birti",
+ "bisli",
+ "bitmu",
+ "bitni",
+ "blabi",
+ "blaci",
+ "blanu",
+ "bliku",
+ "bloti",
+ "bolci",
+ "bongu",
+ "boske",
+ "botpi",
+ "boxfo",
+ "boxna",
+ "bradi",
+ "brano",
+ "bratu",
+ "brazo",
+ "bredi",
+ "bridi",
+ "brife",
+ "briju",
+ "brito",
+ "brivo",
+ "broda",
+ "bruna",
+ "budjo",
+ "bukpu",
+ "bumru",
+ "bunda",
+ "bunre",
+ "burcu",
+ "burna",
+ "cabna",
+ "cabra",
+ "cacra",
+ "cadga",
+ "cadzu",
+ "cafne",
+ "cagna",
+ "cakla",
+ "calku",
+ "calse",
+ "canci",
+ "cando",
+ "cange",
+ "canja",
+ "canko",
+ "canlu",
+ "canpa",
+ "canre",
+ "canti",
+ "carce",
+ "carfu",
+ "carmi",
+ "carna",
+ "cartu",
+ "carvi",
+ "casnu",
+ "catke",
+ "catlu",
+ "catni",
+ "catra",
+ "caxno",
+ "cecla",
+ "cecmu",
+ "cedra",
+ "cenba",
+ "censa",
+ "centi",
+ "cerda",
+ "cerni",
+ "certu",
+ "cevni",
+ "cfale",
+ "cfari",
+ "cfika",
+ "cfila",
+ "cfine",
+ "cfipu",
+ "ciblu",
+ "cicna",
+ "cidja",
+ "cidni",
+ "cidro",
+ "cifnu",
+ "cigla",
+ "cikna",
+ "cikre",
+ "ciksi",
+ "cilce",
+ "cilfu",
+ "cilmo",
+ "cilre",
+ "cilta",
+ "cimde",
+ "cimni",
+ "cinba",
+ "cindu",
+ "cinfo",
+ "cinje",
+ "cinki",
+ "cinla",
+ "cinmo",
+ "cinri",
+ "cinse",
+ "cinta",
+ "cinza",
+ "cipni",
+ "cipra",
+ "cirko",
+ "cirla",
+ "ciska",
+ "cisma",
+ "cisni",
+ "ciste",
+ "citka",
+ "citno",
+ "citri",
+ "citsi",
+ "civla",
+ "cizra",
+ "ckabu",
+ "ckafi",
+ "ckaji",
+ "ckana",
+ "ckape",
+ "ckasu",
+ "ckeji",
+ "ckiku",
+ "ckilu",
+ "ckini",
+ "ckire",
+ "ckule",
+ "ckunu",
+ "cladu",
+ "clani",
+ "claxu",
+ "cletu",
+ "clika",
+ "clinu",
+ "clira",
+ "clite",
+ "cliva",
+ "clupa",
+ "cmaci",
+ "cmalu",
+ "cmana",
+ "cmavo",
+ "cmene",
+ "cmeta",
+ "cmevo",
+ "cmila",
+ "cmima",
+ "cmoni",
+ "cnano",
+ "cnebo",
+ "cnemu",
+ "cnici",
+ "cnino",
+ "cnisa",
+ "cnita",
+ "cokcu",
+ "condi",
+ "conka",
+ "corci",
+ "cortu",
+ "cpacu",
+ "cpana",
+ "cpare",
+ "cpedu",
+ "cpina",
+ "cradi",
+ "crane",
+ "creka",
+ "crepu",
+ "cribe",
+ "crida",
+ "crino",
+ "cripu",
+ "crisa",
+ "critu",
+ "ctaru",
+ "ctebi",
+ "cteki",
+ "ctile",
+ "ctino",
+ "ctuca",
+ "cukla",
+ "cukre",
+ "cukta",
+ "culno",
+ "cumki",
+ "cumla",
+ "cunmi",
+ "cunso",
+ "cuntu",
+ "cupra",
+ "curmi",
+ "curnu",
+ "curve",
+ "cusku",
+ "cusna",
+ "cutci",
+ "cutne",
+ "cuxna",
+ "dacru",
+ "dacti",
+ "dadjo",
+ "dakfu",
+ "dakli",
+ "damba",
+ "damri",
+ "dandu",
+ "danfu",
+ "danlu",
+ "danmo",
+ "danre",
+ "dansu",
+ "danti",
+ "daplu",
+ "dapma",
+ "darca",
+ "dargu",
+ "darlu",
+ "darno",
+ "darsi",
+ "darxi",
+ "daski",
+ "dasni",
+ "daspo",
+ "dasri",
+ "datka",
+ "datni",
+ "datro",
+ "decti",
+ "degji",
+ "dejni",
+ "dekpu",
+ "dekto",
+ "delno",
+ "dembi",
+ "denci",
+ "denmi",
+ "denpa",
+ "dertu",
+ "derxi",
+ "desku",
+ "detri",
+ "dicma",
+ "dicra",
+ "didni",
+ "digno",
+ "dikca",
+ "diklo",
+ "dikni",
+ "dilcu",
+ "dilma",
+ "dilnu",
+ "dimna",
+ "dindi",
+ "dinju",
+ "dinko",
+ "dinso",
+ "dirba",
+ "dirce",
+ "dirgo",
+ "disko",
+ "ditcu",
+ "divzi",
+ "dizlo",
+ "djacu",
+ "djedi",
+ "djica",
+ "djine",
+ "djuno",
+ "donri",
+ "dotco",
+ "draci",
+ "drani",
+ "drata",
+ "drudi",
+ "dugri",
+ "dukse",
+ "dukti",
+ "dunda",
+ "dunja",
+ "dunku",
+ "dunli",
+ "dunra",
+ "dutso",
+ "dzena",
+ "dzipo",
+ "facki",
+ "fadni",
+ "fagri",
+ "falnu",
+ "famti",
+ "fancu",
+ "fange",
+ "fanmo",
+ "fanri",
+ "fanta",
+ "fanva",
+ "fanza",
+ "fapro",
+ "farka",
+ "farlu",
+ "farna",
+ "farvi",
+ "fasnu",
+ "fatci",
+ "fatne",
+ "fatri",
+ "febvi",
+ "fegli",
+ "femti",
+ "fendi",
+ "fengu",
+ "fenki",
+ "fenra",
+ "fenso",
+ "fepni",
+ "fepri",
+ "ferti",
+ "festi",
+ "fetsi",
+ "figre",
+ "filso",
+ "finpe",
+ "finti",
+ "firca",
+ "fisli",
+ "fizbu",
+ "flaci",
+ "flalu",
+ "flani",
+ "flecu",
+ "flese",
+ "fliba",
+ "flira",
+ "foldi",
+ "fonmo",
+ "fonxa",
+ "forca",
+ "forse",
+ "fraso",
+ "frati",
+ "fraxu",
+ "frica",
+ "friko",
+ "frili",
+ "frinu",
+ "friti",
+ "frumu",
+ "fukpi",
+ "fulta",
+ "funca",
+ "fusra",
+ "fuzme",
+ "gacri",
+ "gadri",
+ "galfi",
+ "galtu",
+ "galxe",
+ "ganlo",
+ "ganra",
+ "ganse",
+ "ganti",
+ "ganxo",
+ "ganzu",
+ "gapci",
+ "gapru",
+ "garna",
+ "gasnu",
+ "gaspo",
+ "gasta",
+ "genja",
+ "gento",
+ "genxu",
+ "gerku",
+ "gerna",
+ "gidva",
+ "gigdo",
+ "ginka",
+ "girzu",
+ "gismu",
+ "glare",
+ "gleki",
+ "gletu",
+ "glico",
+ "glife",
+ "glosa",
+ "gluta",
+ "gocti",
+ "gomsi",
+ "gotro",
+ "gradu",
+ "grafu",
+ "grake",
+ "grana",
+ "grasu",
+ "grava",
+ "greku",
+ "grusi",
+ "grute",
+ "gubni",
+ "gugde",
+ "gugle",
+ "gumri",
+ "gundi",
+ "gunka",
+ "gunma",
+ "gunro",
+ "gunse",
+ "gunta",
+ "gurni",
+ "guska",
+ "gusni",
+ "gusta",
+ "gutci",
+ "gutra",
+ "guzme",
+ "jabre",
+ "jadni",
+ "jakne",
+ "jalge",
+ "jalna",
+ "jalra",
+ "jamfu",
+ "jamna",
+ "janbe",
+ "janco",
+ "janli",
+ "jansu",
+ "janta",
+ "jarbu",
+ "jarco",
+ "jarki",
+ "jaspu",
+ "jatna",
+ "javni",
+ "jbama",
+ "jbari",
+ "jbena",
+ "jbera",
+ "jbini",
+ "jdari",
+ "jdice",
+ "jdika",
+ "jdima",
+ "jdini",
+ "jduli",
+ "jecta",
+ "jeftu",
+ "jegvo",
+ "jelca",
+ "jemna",
+ "jenca",
+ "jendu",
+ "jenmi",
+ "jensi",
+ "jerna",
+ "jersi",
+ "jerxo",
+ "jesni",
+ "jetce",
+ "jetnu",
+ "jgalu",
+ "jganu",
+ "jgari",
+ "jgena",
+ "jgina",
+ "jgira",
+ "jgita",
+ "jibni",
+ "jibri",
+ "jicla",
+ "jicmu",
+ "jijnu",
+ "jikca",
+ "jikfi",
+ "jikni",
+ "jikru",
+ "jilka",
+ "jilra",
+ "jimca",
+ "jimpe",
+ "jimte",
+ "jinci",
+ "jinda",
+ "jinga",
+ "jinku",
+ "jinme",
+ "jinru",
+ "jinsa",
+ "jinto",
+ "jinvi",
+ "jinzi",
+ "jipci",
+ "jipno",
+ "jirna",
+ "jisra",
+ "jitfa",
+ "jitro",
+ "jivbu",
+ "jivna",
+ "jmaji",
+ "jmifa",
+ "jmina",
+ "jmive",
+ "jonse",
+ "jordo",
+ "jorne",
+ "jubme",
+ "judri",
+ "jufra",
+ "jukni",
+ "jukpa",
+ "julne",
+ "julro",
+ "jundi",
+ "jungo",
+ "junla",
+ "junri",
+ "junta",
+ "jurme",
+ "jursa",
+ "jutsi",
+ "juxre",
+ "jvinu",
+ "jviso",
+ "kabri",
+ "kacma",
+ "kadno",
+ "kafke",
+ "kagni",
+ "kajde",
+ "kajna",
+ "kakne",
+ "kakpa",
+ "kalci",
+ "kalri",
+ "kalsa",
+ "kalte",
+ "kamju",
+ "kamni",
+ "kampu",
+ "kamre",
+ "kanba",
+ "kancu",
+ "kandi",
+ "kanji",
+ "kanla",
+ "kanpe",
+ "kanro",
+ "kansa",
+ "kantu",
+ "kanxe",
+ "karbi",
+ "karce",
+ "karda",
+ "kargu",
+ "karli",
+ "karni",
+ "katci",
+ "katna",
+ "kavbu",
+ "kazra",
+ "kecti",
+ "kekli",
+ "kelci",
+ "kelvo",
+ "kenka",
+ "kenra",
+ "kensa",
+ "kerfa",
+ "kerlo",
+ "kesri",
+ "ketco",
+ "ketsu",
+ "kevna",
+ "kibro",
+ "kicne",
+ "kijno",
+ "kilto",
+ "kinda",
+ "kinli",
+ "kisto",
+ "klaji",
+ "klaku",
+ "klama",
+ "klani",
+ "klesi",
+ "kliki",
+ "klina",
+ "kliru",
+ "kliti",
+ "klupe",
+ "kluza",
+ "kobli",
+ "kogno",
+ "kojna",
+ "kokso",
+ "kolme",
+ "komcu",
+ "konju",
+ "korbi",
+ "korcu",
+ "korka",
+ "korvo",
+ "kosmu",
+ "kosta",
+ "krali",
+ "kramu",
+ "krasi",
+ "krati",
+ "krefu",
+ "krici",
+ "krili",
+ "krinu",
+ "krixa",
+ "kruca",
+ "kruji",
+ "kruvi",
+ "kubli",
+ "kucli",
+ "kufra",
+ "kukte",
+ "kulnu",
+ "kumfa",
+ "kumte",
+ "kunra",
+ "kunti",
+ "kurfa",
+ "kurji",
+ "kurki",
+ "kuspe",
+ "kusru",
+ "labno",
+ "lacni",
+ "lacpu",
+ "lacri",
+ "ladru",
+ "lafti",
+ "lakne",
+ "lakse",
+ "laldo",
+ "lalxu",
+ "lamji",
+ "lanbi",
+ "lanci",
+ "landa",
+ "lanka",
+ "lanli",
+ "lanme",
+ "lante",
+ "lanxe",
+ "lanzu",
+ "larcu",
+ "larva",
+ "lasna",
+ "lastu",
+ "latmo",
+ "latna",
+ "lazni",
+ "lebna",
+ "lelxe",
+ "lenga",
+ "lenjo",
+ "lenku",
+ "lerci",
+ "lerfu",
+ "libjo",
+ "lidne",
+ "lifri",
+ "lijda",
+ "limfa",
+ "limna",
+ "lince",
+ "lindi",
+ "linga",
+ "linji",
+ "linsi",
+ "linto",
+ "lisri",
+ "liste",
+ "litce",
+ "litki",
+ "litru",
+ "livga",
+ "livla",
+ "logji",
+ "loglo",
+ "lojbo",
+ "loldi",
+ "lorxu",
+ "lubno",
+ "lujvo",
+ "luksi",
+ "lumci",
+ "lunbe",
+ "lunra",
+ "lunsa",
+ "luska",
+ "lusto",
+ "mabla",
+ "mabru",
+ "macnu",
+ "majga",
+ "makcu",
+ "makfa",
+ "maksi",
+ "malsi",
+ "mamta",
+ "manci",
+ "manfo",
+ "mango",
+ "manku",
+ "manri",
+ "mansa",
+ "manti",
+ "mapku",
+ "mapni",
+ "mapra",
+ "mapti",
+ "marbi",
+ "marce",
+ "marde",
+ "margu",
+ "marji",
+ "marna",
+ "marxa",
+ "masno",
+ "masti",
+ "matci",
+ "matli",
+ "matne",
+ "matra",
+ "mavji",
+ "maxri",
+ "mebri",
+ "megdo",
+ "mekso",
+ "melbi",
+ "meljo",
+ "melmi",
+ "menli",
+ "menre",
+ "mensi",
+ "mentu",
+ "merko",
+ "merli",
+ "metfo",
+ "mexno",
+ "midju",
+ "mifra",
+ "mikce",
+ "mikri",
+ "milti",
+ "milxe",
+ "minde",
+ "minji",
+ "minli",
+ "minra",
+ "mintu",
+ "mipri",
+ "mirli",
+ "misno",
+ "misro",
+ "mitre",
+ "mixre",
+ "mlana",
+ "mlatu",
+ "mleca",
+ "mledi",
+ "mluni",
+ "mogle",
+ "mokca",
+ "moklu",
+ "molki",
+ "molro",
+ "morji",
+ "morko",
+ "morna",
+ "morsi",
+ "mosra",
+ "mraji",
+ "mrilu",
+ "mruli",
+ "mucti",
+ "mudri",
+ "mugle",
+ "mukti",
+ "mulno",
+ "munje",
+ "mupli",
+ "murse",
+ "murta",
+ "muslo",
+ "mutce",
+ "muvdu",
+ "muzga",
+ "nabmi",
+ "nakni",
+ "nalci",
+ "namcu",
+ "nanba",
+ "nanca",
+ "nandu",
+ "nanla",
+ "nanmu",
+ "nanvi",
+ "narge",
+ "narju",
+ "natfe",
+ "natmi",
+ "natsi",
+ "navni",
+ "naxle",
+ "nazbi",
+ "nejni",
+ "nelci",
+ "nenri",
+ "nerde",
+ "nibli",
+ "nicfa",
+ "nicte",
+ "nikle",
+ "nilce",
+ "nimre",
+ "ninja",
+ "ninmu",
+ "nirna",
+ "nitcu",
+ "nivji",
+ "nixli",
+ "nobli",
+ "norgo",
+ "notci",
+ "nudle",
+ "nukni",
+ "nunmu",
+ "nupre",
+ "nurma",
+ "nusna",
+ "nutka",
+ "nutli",
+ "nuzba",
+ "nuzlo",
+ "pacna",
+ "pagbu",
+ "pagre",
+ "pajni",
+ "palci",
+ "palku",
+ "palma",
+ "palne",
+ "palpi",
+ "palta",
+ "pambe",
+ "pamga",
+ "panci",
+ "pandi",
+ "panje",
+ "panka",
+ "panlo",
+ "panpi",
+ "panra",
+ "pante",
+ "panzi",
+ "papri",
+ "parbi",
+ "pardu",
+ "parji",
+ "pastu",
+ "patfu",
+ "patlu",
+ "patxu",
+ "paznu",
+ "pelji",
+ "pelxu",
+ "pemci",
+ "penbi",
+ "pencu",
+ "pendo",
+ "penmi",
+ "pensi",
+ "pentu",
+ "perli",
+ "pesxu",
+ "petso",
+ "pevna",
+ "pezli",
+ "picti",
+ "pijne",
+ "pikci",
+ "pikta",
+ "pilda",
+ "pilji",
+ "pilka",
+ "pilno",
+ "pimlu",
+ "pinca",
+ "pindi",
+ "pinfu",
+ "pinji",
+ "pinka",
+ "pinsi",
+ "pinta",
+ "pinxe",
+ "pipno",
+ "pixra",
+ "plana",
+ "platu",
+ "pleji",
+ "plibu",
+ "plini",
+ "plipe",
+ "plise",
+ "plita",
+ "plixa",
+ "pluja",
+ "pluka",
+ "pluta",
+ "pocli",
+ "polje",
+ "polno",
+ "ponjo",
+ "ponse",
+ "poplu",
+ "porpi",
+ "porsi",
+ "porto",
+ "prali",
+ "prami",
+ "prane",
+ "preja",
+ "prenu",
+ "preri",
+ "preti",
+ "prije",
+ "prina",
+ "pritu",
+ "proga",
+ "prosa",
+ "pruce",
+ "pruni",
+ "pruri",
+ "pruxi",
+ "pulce",
+ "pulji",
+ "pulni",
+ "punji",
+ "punli",
+ "pupsu",
+ "purci",
+ "purdi",
+ "purmo",
+ "racli",
+ "ractu",
+ "radno",
+ "rafsi",
+ "ragbi",
+ "ragve",
+ "rakle",
+ "rakso",
+ "raktu",
+ "ralci",
+ "ralju",
+ "ralte",
+ "randa",
+ "rango",
+ "ranji",
+ "ranmi",
+ "ransu",
+ "ranti",
+ "ranxi",
+ "rapli",
+ "rarna",
+ "ratcu",
+ "ratni",
+ "rebla",
+ "rectu",
+ "rekto",
+ "remna",
+ "renro",
+ "renvi",
+ "respa",
+ "rexsa",
+ "ricfu",
+ "rigni",
+ "rijno",
+ "rilti",
+ "rimni",
+ "rinci",
+ "rindo",
+ "rinju",
+ "rinka",
+ "rinsa",
+ "rirci",
+ "rirni",
+ "rirxe",
+ "rismi",
+ "risna",
+ "ritli",
+ "rivbi",
+ "rokci",
+ "romge",
+ "romlo",
+ "ronte",
+ "ropno",
+ "rorci",
+ "rotsu",
+ "rozgu",
+ "ruble",
+ "rufsu",
+ "runme",
+ "runta",
+ "rupnu",
+ "rusko",
+ "rutni",
+ "sabji",
+ "sabnu",
+ "sacki",
+ "saclu",
+ "sadjo",
+ "sakci",
+ "sakli",
+ "sakta",
+ "salci",
+ "salpo",
+ "salri",
+ "salta",
+ "samcu",
+ "sampu",
+ "sanbu",
+ "sance",
+ "sanga",
+ "sanji",
+ "sanli",
+ "sanmi",
+ "sanso",
+ "santa",
+ "sarcu",
+ "sarji",
+ "sarlu",
+ "sarni",
+ "sarxe",
+ "saske",
+ "satci",
+ "satre",
+ "savru",
+ "sazri",
+ "sefsi",
+ "sefta",
+ "sekre",
+ "selci",
+ "selfu",
+ "semto",
+ "senci",
+ "sengi",
+ "senpi",
+ "senta",
+ "senva",
+ "sepli",
+ "serti",
+ "sesre",
+ "setca",
+ "sevzi",
+ "sfani",
+ "sfasa",
+ "sfofa",
+ "sfubu",
+ "sibli",
+ "siclu",
+ "sicni",
+ "sicpi",
+ "sidbo",
+ "sidju",
+ "sigja",
+ "sigma",
+ "sikta",
+ "silka",
+ "silna",
+ "simlu",
+ "simsa",
+ "simxu",
+ "since",
+ "sinma",
+ "sinso",
+ "sinxa",
+ "sipna",
+ "sirji",
+ "sirxo",
+ "sisku",
+ "sisti",
+ "sitna",
+ "sivni",
+ "skaci",
+ "skami",
+ "skapi",
+ "skari",
+ "skicu",
+ "skiji",
+ "skina",
+ "skori",
+ "skoto",
+ "skuba",
+ "skuro",
+ "slabu",
+ "slaka",
+ "slami",
+ "slanu",
+ "slari",
+ "slasi",
+ "sligu",
+ "slilu",
+ "sliri",
+ "slovo",
+ "sluji",
+ "sluni",
+ "smacu",
+ "smadi",
+ "smaji",
+ "smaka",
+ "smani",
+ "smela",
+ "smoka",
+ "smuci",
+ "smuni",
+ "smusu",
+ "snada",
+ "snanu",
+ "snidu",
+ "snime",
+ "snipa",
+ "snuji",
+ "snura",
+ "snuti",
+ "sobde",
+ "sodna",
+ "sodva",
+ "softo",
+ "solji",
+ "solri",
+ "sombo",
+ "sonci",
+ "sorcu",
+ "sorgu",
+ "sorni",
+ "sorta",
+ "sovda",
+ "spaji",
+ "spali",
+ "spano",
+ "spati",
+ "speni",
+ "spero",
+ "spisa",
+ "spita",
+ "spofu",
+ "spoja",
+ "spuda",
+ "sputu",
+ "sraji",
+ "sraku",
+ "sralo",
+ "srana",
+ "srasu",
+ "srera",
+ "srito",
+ "sruma",
+ "sruri",
+ "stace",
+ "stagi",
+ "staku",
+ "stali",
+ "stani",
+ "stapa",
+ "stasu",
+ "stati",
+ "steba",
+ "steci",
+ "stedu",
+ "stela",
+ "stero",
+ "stici",
+ "stidi",
+ "stika",
+ "stizu",
+ "stodi",
+ "stuna",
+ "stura",
+ "stuzi",
+ "sucta",
+ "sudga",
+ "sufti",
+ "suksa",
+ "sumji",
+ "sumne",
+ "sumti",
+ "sunga",
+ "sunla",
+ "surla",
+ "sutra",
+ "tabno",
+ "tabra",
+ "tadji",
+ "tadni",
+ "tagji",
+ "taksi",
+ "talsa",
+ "tamca",
+ "tamji",
+ "tamne",
+ "tanbo",
+ "tance",
+ "tanjo",
+ "tanko",
+ "tanru",
+ "tansi",
+ "tanxe",
+ "tapla",
+ "tarbi",
+ "tarci",
+ "tarla",
+ "tarmi",
+ "tarti",
+ "taske",
+ "tasmi",
+ "tasta",
+ "tatpi",
+ "tatru",
+ "tavla",
+ "taxfu",
+ "tcaci",
+ "tcadu",
+ "tcana",
+ "tcati",
+ "tcaxe",
+ "tcena",
+ "tcese",
+ "tcica",
+ "tcidu",
+ "tcika",
+ "tcila",
+ "tcima",
+ "tcini",
+ "tcita",
+ "temci",
+ "temse",
+ "tende",
+ "tenfa",
+ "tengu",
+ "terdi",
+ "terpa",
+ "terto",
+ "tifri",
+ "tigni",
+ "tigra",
+ "tikpa",
+ "tilju",
+ "tinbe",
+ "tinci",
+ "tinsa",
+ "tirna",
+ "tirse",
+ "tirxu",
+ "tisna",
+ "titla",
+ "tivni",
+ "tixnu",
+ "toknu",
+ "toldi",
+ "tonga",
+ "tordu",
+ "torni",
+ "torso",
+ "traji",
+ "trano",
+ "trati",
+ "trene",
+ "tricu",
+ "trina",
+ "trixe",
+ "troci",
+ "tsaba",
+ "tsali",
+ "tsani",
+ "tsapi",
+ "tsiju",
+ "tsina",
+ "tsuku",
+ "tubnu",
+ "tubra",
+ "tugni",
+ "tujli",
+ "tumla",
+ "tunba",
+ "tunka",
+ "tunlo",
+ "tunta",
+ "tuple",
+ "turko",
+ "turni",
+ "tutci",
+ "tutle",
+ "tutra",
+ "vacri",
+ "vajni",
+ "valsi",
+ "vamji",
+ "vamtu",
+ "vanbi",
+ "vanci",
+ "vanju",
+ "vasru",
+ "vasxu",
+ "vecnu",
+ "vedli",
+ "venfu",
+ "vensa",
+ "vente",
+ "vepre",
+ "verba",
+ "vibna",
+ "vidni",
+ "vidru",
+ "vifne",
+ "vikmi",
+ "viknu",
+ "vimcu",
+ "vindu",
+ "vinji",
+ "vinta",
+ "vipsi",
+ "virnu",
+ "viska",
+ "vitci",
+ "vitke",
+ "vitno",
+ "vlagi",
+ "vlile",
+ "vlina",
+ "vlipa",
+ "vofli",
+ "voksa",
+ "volve",
+ "vorme",
+ "vraga",
+ "vreji",
+ "vreta",
+ "vrici",
+ "vrude",
+ "vrusi",
+ "vubla",
+ "vujnu",
+ "vukna",
+ "vukro",
+ "xabju",
+ "xadba",
+ "xadji",
+ "xadni",
+ "xagji",
+ "xagri",
+ "xajmi",
+ "xaksu",
+ "xalbo",
+ "xalka",
+ "xalni",
+ "xamgu",
+ "xampo",
+ "xamsi",
+ "xance",
+ "xango",
+ "xanka",
+ "xanri",
+ "xansa",
+ "xanto",
+ "xarci",
+ "xarju",
+ "xarnu",
+ "xasli",
+ "xasne",
+ "xatra",
+ "xatsi",
+ "xazdo",
+ "xebni",
+ "xebro",
+ "xecto",
+ "xedja",
+ "xekri",
+ "xelso",
+ "xendo",
+ "xenru",
+ "xexso",
+ "xigzo",
+ "xindo",
+ "xinmo",
+ "xirma",
+ "xislu",
+ "xispo",
+ "xlali",
+ "xlura",
+ "xorbo",
+ "xorlo",
+ "xotli",
+ "xrabo",
+ "xrani",
+ "xriso",
+ "xrotu",
+ "xruba",
+ "xruki",
+ "xrula",
+ "xruti",
+ "xukmi",
+ "xulta",
+ "xunre",
+ "xurdo",
+ "xusra",
+ "xutla",
+ "zabna",
+ "zajba",
+ "zalvi",
+ "zanru",
+ "zarci",
+ "zargu",
+ "zasni",
+ "zasti",
+ "zbabu",
+ "zbani",
+ "zbasu",
+ "zbepi",
+ "zdani",
+ "zdile",
+ "zekri",
+ "zenba",
+ "zepti",
+ "zetro",
+ "zevla",
+ "zgadi",
+ "zgana",
+ "zgike",
+ "zifre",
+ "zinki",
+ "zirpu",
+ "zivle",
+ "zmadu",
+ "zmiku",
+ "zucna",
+ "zukte",
+ "zumri",
+ "zungi",
+ "zunle",
+ "zunti",
+ "zutse",
+ "zvati",
+ "zviki",
+ "jbobau",
+ "jbopre",
+ "karsna",
+ "cabdei",
+ "zunsna",
+ "gendra",
+ "glibau",
+ "nintadni",
+ "pavyseljirna",
+ "vlaste",
+ "selbri",
+ "latro'a",
+ "zdakemkulgu'a",
+ "mriste",
+ "selsku",
+ "fu'ivla",
+ "tolmo'i",
+ "snavei",
+ "xagmau",
+ "retsku",
+ "ckupau",
+ "skudji",
+ "smudra",
+ "prulamdei",
+ "vokta'a",
+ "tinju'i",
+ "jefyfa'o",
+ "bavlamdei",
+ "kinzga",
+ "jbocre",
+ "jbovla",
+ "xauzma",
+ "selkei",
+ "xuncku",
+ "spusku",
+ "jbogu'e",
+ "pampe'o",
+ "bripre",
+ "jbosnu",
+ "zi'evla",
+ "gimste",
+ "tolzdi",
+ "velski",
+ "samselpla",
+ "cnegau",
+ "velcki",
+ "selja'e",
+ "fasybau",
+ "zanfri",
+ "reisku",
+ "favgau",
+ "jbota'a",
+ "rejgau",
+ "malgli",
+ "zilkai",
+ "keidji",
+ "tersu'i",
+ "jbofi'e",
+ "cnima'o",
+ "mulgau",
+ "ningau",
+ "ponbau",
+ "mrobi'o",
+ "rarbau",
+ "zmanei",
+ "famyma'o",
+ "vacysai",
+ "jetmlu",
+ "jbonunsla",
+ "nunpe'i",
+ "fa'orma'o",
+ "crezenzu'e",
+ "jbojbe",
+ "cmicu'a",
+ "zilcmi",
+ "tolcando",
+ "zukcfu",
+ "depybu'i",
+ "mencre",
+ "matmau",
+ "nunctu",
+ "selma'o",
+ "titnanba",
+ "naldra",
+ "jvajvo",
+ "nunsnu",
+ "nerkla",
+ "cimjvo",
+ "muvgau",
+ "zipcpi",
+ "runbau",
+ "faumlu",
+ "terbri",
+ "balcu'e",
+ "dragau",
+ "smuvelcki",
+ "piksku",
+ "selpli",
+ "bregau",
+ "zvafa'i",
+ "ci'izra",
+ "noltruti'u",
+ "samtci",
+ "snaxa'a",
+ }), 4)
+ {
+ populate_maps();
+ }
+ };
+}
+
+#endif
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 48739bc2d..bc503c73c 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -792,7 +792,7 @@ simple_wallet::simple_wallet() , m_in_manual_refresh(false) , m_current_subaddress_account(0) { - m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), tr("start_mining [<number_of_threads>] - Start mining in daemon")); + m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), tr("start_mining [<number_of_threads>] [bg_mining] [ignore_battery] - Start mining in daemon (bg_mining and ignore_battery are optional booleans)")); m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), tr("Stop mining in daemon")); m_cmd_binder.set_handler("save_bc", boost::bind(&simple_wallet::save_bc, this, _1), tr("Save current blockchain data")); m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), tr("Synchronize transactions and balance")); @@ -1450,8 +1450,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) } } } - m_wallet->set_refresh_from_block_height(m_restore_height); } + if (m_restoring) + m_wallet->set_refresh_from_block_height(m_restore_height); } else { @@ -1870,8 +1871,8 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args) bool ok = true; size_t max_mining_threads_count = (std::max)(tools::get_max_concurrency(), static_cast<unsigned>(2)); size_t arg_size = args.size(); - if(arg_size >= 3) req.ignore_battery = args[2] == "true"; - if(arg_size >= 2) req.do_background_mining = args[1] == "true"; + if(arg_size >= 3) req.ignore_battery = is_it_true(args[2]); + if(arg_size >= 2) req.do_background_mining = is_it_true(args[1]); if(arg_size >= 1) { uint16_t num = 1; @@ -3539,12 +3540,18 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) fail_msg_writer() << tr("This is a watch only wallet"); return true; } + if (args_.size() > 1 || (args_.size() == 1 && args_[0] != "export")) + { + fail_msg_writer() << tr("usage: sign_transfer [export]"); + return true; + } if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } + const bool export_raw = args_.size() == 1; std::vector<tools::wallet2::pending_tx> ptx; try { - bool r = m_wallet->sign_tx("unsigned_monero_tx", "signed_monero_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); }); + bool r = m_wallet->sign_tx("unsigned_monero_tx", "signed_monero_tx", ptx, [&](const tools::wallet2::unsigned_tx_set &tx){ return accept_loaded_tx(tx); }, export_raw); if (!r) { fail_msg_writer() << tr("Failed to sign transaction"); @@ -3565,6 +3572,17 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) txids_as_text += epee::string_tools::pod_to_hex(get_transaction_hash(t.tx)); } success_msg_writer(true) << tr("Transaction successfully signed to file ") << "signed_monero_tx" << ", txid " << txids_as_text; + if (export_raw) + { + std::string rawfiles_as_text; + for (size_t i = 0; i < ptx.size(); ++i) + { + if (i > 0) + rawfiles_as_text += ", "; + rawfiles_as_text += "signed_monero_tx_raw" + (ptx.size() == 1 ? "" : ("_" + std::to_string(i))); + } + success_msg_writer(true) << tr("Transaction raw hex data exported to ") << rawfiles_as_text; + } return true; } //---------------------------------------------------------------------------------------------------- diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index b0ce28b9b..fdb3bf976 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -81,8 +81,8 @@ using namespace cryptonote; // arbitrary, used to generate different hashes from the same input #define CHACHA8_KEY_TAIL 0x8c -#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\003" -#define SIGNED_TX_PREFIX "Monero signed tx set\003" +#define UNSIGNED_TX_PREFIX "Monero unsigned tx set\004" +#define SIGNED_TX_PREFIX "Monero signed tx set\004" #define RECENT_OUTPUT_RATIO (0.5) // 50% of outputs are from the recent zone #define RECENT_OUTPUT_ZONE ((time_t)(1.8 * 86400)) // last 1.8 day makes up the recent zone (taken from monerolink.pdf, Miller et al) @@ -3603,7 +3603,8 @@ bool wallet2::save_tx(const std::vector<pending_tx>& ptx_vector, const std::stri return false; } LOG_PRINT_L2("Saving unsigned tx data: " << oss.str()); - return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + oss.str()); + std::string ciphertext = encrypt_with_view_secret_key(oss.str()); + return epee::file_io_utils::save_string_to_file(filename, std::string(UNSIGNED_TX_PREFIX) + ciphertext); } //---------------------------------------------------------------------------------------------------- bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs) @@ -3621,22 +3622,55 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx LOG_PRINT_L0("Failed to load from " << unsigned_filename); return false; } - const size_t magiclen = strlen(UNSIGNED_TX_PREFIX); + const size_t magiclen = strlen(UNSIGNED_TX_PREFIX) - 1; if (strncmp(s.c_str(), UNSIGNED_TX_PREFIX, magiclen)) { LOG_PRINT_L0("Bad magic from " << unsigned_filename); return false; } s = s.substr(magiclen); - try + const char version = s[0]; + s = s.substr(1); + if (version == '\003') { - std::istringstream iss(s); - boost::archive::portable_binary_iarchive ar(iss); - ar >> exported_txs; + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + } + catch (...) + { + LOG_PRINT_L0("Failed to parse data from " << unsigned_filename); + return false; + } + } + else if (version == '\004') + { + try + { + s = decrypt_with_view_secret_key(s); + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> exported_txs; + } + catch (...) + { + LOG_PRINT_L0("Failed to parse data from " << unsigned_filename); + return false; + } + } + catch (const std::exception &e) + { + LOG_PRINT_L0("Failed to decrypt " << unsigned_filename << ": " << e.what()); + return false; + } } - catch (...) + else { - LOG_PRINT_L0("Failed to parse data from " << unsigned_filename); + LOG_PRINT_L0("Unsupported version in " << unsigned_filename); return false; } LOG_PRINT_L1("Loaded tx unsigned data from binary: " << exported_txs.txes.size() << " transactions"); @@ -3644,7 +3678,7 @@ bool wallet2::load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func) +bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, std::function<bool(const unsigned_tx_set&)> accept_func, bool export_raw) { unsigned_tx_set exported_txs; if(!load_unsigned_tx(unsigned_filename, exported_txs)) @@ -3655,11 +3689,11 @@ bool wallet2::sign_tx(const std::string &unsigned_filename, const std::string &s LOG_PRINT_L1("Transactions rejected by callback"); return false; } - return sign_tx(exported_txs, signed_filename, txs); + return sign_tx(exported_txs, signed_filename, txs, export_raw); } //---------------------------------------------------------------------------------------------------- -bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs) +bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &txs, bool export_raw) { import_outputs(exported_txs.transfers); @@ -3734,8 +3768,28 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_f { return false; } - LOG_PRINT_L3("Saving signed tx data: " << oss.str()); - return epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + oss.str()); + LOG_PRINT_L3("Saving signed tx data (with encryption): " << oss.str()); + std::string ciphertext = encrypt_with_view_secret_key(oss.str()); + if (!epee::file_io_utils::save_string_to_file(signed_filename, std::string(SIGNED_TX_PREFIX) + ciphertext)) + { + LOG_PRINT_L0("Failed to save file to " << signed_filename); + return false; + } + // export signed raw tx without encryption + if (export_raw) + { + for (size_t i = 0; i < signed_txes.ptx.size(); ++i) + { + std::string tx_as_hex = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(signed_txes.ptx[i].tx)); + std::string raw_filename = signed_filename + "_raw" + (signed_txes.ptx.size() == 1 ? "" : ("_" + std::to_string(i))); + if (!epee::file_io_utils::save_string_to_file(raw_filename, tx_as_hex)) + { + LOG_PRINT_L0("Failed to save file to " << raw_filename); + return false; + } + } + } + return true; } //---------------------------------------------------------------------------------------------------- bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func) @@ -3755,22 +3809,55 @@ bool wallet2::load_tx(const std::string &signed_filename, std::vector<tools::wal LOG_PRINT_L0("Failed to load from " << signed_filename); return false; } - const size_t magiclen = strlen(SIGNED_TX_PREFIX); + const size_t magiclen = strlen(SIGNED_TX_PREFIX) - 1; if (strncmp(s.c_str(), SIGNED_TX_PREFIX, magiclen)) { LOG_PRINT_L0("Bad magic from " << signed_filename); return false; } s = s.substr(magiclen); - try + const char version = s[0]; + s = s.substr(1); + if (version == '\003') { - std::istringstream iss(s); - boost::archive::portable_binary_iarchive ar(iss); - ar >> signed_txs; + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> signed_txs; + } + catch (...) + { + LOG_PRINT_L0("Failed to parse data from " << signed_filename); + return false; + } } - catch (...) + else if (version == '\004') + { + try + { + s = decrypt_with_view_secret_key(s); + try + { + std::istringstream iss(s); + boost::archive::portable_binary_iarchive ar(iss); + ar >> signed_txs; + } + catch (...) + { + LOG_PRINT_L0("Failed to parse decrypted data from " << signed_filename); + return false; + } + } + catch (const std::exception &e) + { + LOG_PRINT_L0("Failed to decrypt " << signed_filename << ": " << e.what()); + return false; + } + } + else { - LOG_PRINT_L0("Failed to parse data from " << signed_filename); + LOG_PRINT_L0("Unsupported version in " << signed_filename); return false; } LOG_PRINT_L0("Loaded signed tx data from binary: " << signed_txs.ptx.size() << " transactions"); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 6cc8ec7c4..31afd0b9e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -512,9 +512,9 @@ namespace tools void commit_tx(std::vector<pending_tx>& ptx_vector); bool save_tx(const std::vector<pending_tx>& ptx_vector, const std::string &filename); // load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet - bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL); + bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, std::function<bool(const unsigned_tx_set&)> accept_func = NULL, bool export_raw = false); // sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI - bool sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx); + bool sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_filename, std::vector<wallet2::pending_tx> &ptx, bool export_raw = false); // load unsigned_tx_set from file. bool load_unsigned_tx(const std::string &unsigned_filename, unsigned_tx_set &exported_txs); bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL); diff --git a/tests/unit_tests/dns_resolver.cpp b/tests/unit_tests/dns_resolver.cpp index aca74a93f..8ac86146e 100644 --- a/tests/unit_tests/dns_resolver.cpp +++ b/tests/unit_tests/dns_resolver.cpp @@ -157,3 +157,17 @@ TEST(DNSResolver, GetTXTRecord) addr = tools::DNSResolver::instance().get_dns_format_from_oa_address("donate.getmonero.org"); EXPECT_STREQ("donate.getmonero.org", addr.c_str()); } + +TEST(DNS_PUBLIC, empty) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("").c_str()); } +TEST(DNS_PUBLIC, default) { EXPECT_STREQ("8.8.4.4", tools::dns_utils::parse_dns_public("tcp").c_str()); } +TEST(DNS_PUBLIC, invalid_scheme) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("invalid").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_alpha) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://invalid").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_num1) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_num3) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4.5").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_num4_extra) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4.5.6x").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_num4_range) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4.542.6").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_dot) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4.5.6.").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_num5) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4.5.6.7").c_str()); } +TEST(DNS_PUBLIC, invalid_ip_4_missing) { EXPECT_STREQ("", tools::dns_utils::parse_dns_public("tcp://3.4..7").c_str()); } +TEST(DNS_PUBLIC, valid_ip_lo) { EXPECT_STREQ("127.0.0.1", tools::dns_utils::parse_dns_public("tcp://127.0.0.1").c_str()); } +TEST(DNS_PUBLIC, valid_ip) { EXPECT_STREQ("3.4.5.6", tools::dns_utils::parse_dns_public("tcp://3.4.5.6").c_str()); } diff --git a/tests/unit_tests/mnemonics.cpp b/tests/unit_tests/mnemonics.cpp index 05894adf4..39ec394a1 100644 --- a/tests/unit_tests/mnemonics.cpp +++ b/tests/unit_tests/mnemonics.cpp @@ -45,6 +45,7 @@ #include "mnemonics/french.h" #include "mnemonics/dutch.h" #include "mnemonics/esperanto.h" +#include "mnemonics/lojban.h" #include "mnemonics/english_old.h" #include "mnemonics/language_base.h" #include "mnemonics/singleton.h" @@ -167,7 +168,8 @@ TEST(mnemonics, all_languages) Language::Singleton<Language::Russian>::instance(), Language::Singleton<Language::French>::instance(), Language::Singleton<Language::Dutch>::instance(), - Language::Singleton<Language::Esperanto>::instance() + Language::Singleton<Language::Esperanto>::instance(), + Language::Singleton<Language::Lojban>::instance() }); for (std::vector<Language::Base*>::iterator it = languages.begin(); it != languages.end(); it++) diff --git a/utils/gpg_keys/mishi_choudhary.asc b/utils/gpg_keys/mishi_choudhary.asc new file mode 100644 index 000000000..4112a77c5 --- /dev/null +++ b/utils/gpg_keys/mishi_choudhary.asc @@ -0,0 +1,125 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +Aek4ThYIS63X9+CoREaA8+8fAy0s6TDs15U= +=TQbT +-----END PGP PUBLIC KEY BLOCK----- |