diff options
102 files changed, 2156 insertions, 991 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f794c0d5e..3de9cd5ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ # Contributing to Monero A good way to help is to test, and report bugs. See -[How to Report Bugs Effectively (by Simon Tatham)](http://www.chiark.greenend.org.uk/~sgtatham/bugs.html) +[How to Report Bugs Effectively (by Simon Tatham)](https://www.chiark.greenend.org.uk/~sgtatham/bugs.html) if you want to help that way. Testing is invaluable in making a piece of software solid and usable. @@ -20,7 +20,7 @@ # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# built into libc) for the transcoding. See https://www.gnu.org/software/libiconv # for the list of possible encodings. # The default value is: UTF-8. @@ -285,7 +285,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -318,7 +318,7 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -677,7 +677,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. Do not use file names with spaces, bibtex cannot handle them. See @@ -759,7 +759,7 @@ INPUT = src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv) for the list of # possible encodings. # The default value is: UTF-8. @@ -951,7 +951,7 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: @@ -1094,7 +1094,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1152,12 +1152,12 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# environment (see: https://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1197,7 +1197,7 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1273,7 +1273,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1281,7 +1281,7 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1290,7 +1290,7 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1298,7 +1298,7 @@ QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1306,7 +1306,7 @@ QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1411,7 +1411,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using prerendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1423,7 +1423,7 @@ USE_MATHJAX = NO # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# https://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. @@ -1438,11 +1438,11 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1453,7 +1453,7 @@ MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: https://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1500,7 +1500,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1513,7 +1513,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer ( doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1684,7 +1684,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -2051,7 +2051,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -9,7 +9,7 @@ Portions Copyright (c) 2012-2013 The Cryptonote developers. - Forum: [forum.getmonero.org](https://forum.getmonero.org) - Mail: [dev@getmonero.org](mailto:dev@getmonero.org) - GitHub: [https://github.com/monero-project/monero](https://github.com/monero-project/monero) -- IRC: [#monero-dev on Freenode](http://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4) +- IRC: [#monero-dev on Freenode](https://webchat.freenode.net/?randomnick=1&channels=%23monero-dev&prompt=1&uio=d4) ## Vulnerability response @@ -77,12 +77,12 @@ The Bitcoin donation address is: `1KTexdemPdxSBcG55heUuTjDRYqbC5ZL8H` Core development funding and/or some supporting services are also graciously provided by sponsors: [<img width="80" src="https://static.getmonero.org/images/sponsors/mymonero.png"/>](https://mymonero.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/kitware.png?1"/>](http://kitware.com) -[<img width="100" src="https://static.getmonero.org/images/sponsors/dome9.png"/>](http://dome9.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/araxis.png"/>](http://araxis.com) -[<img width="150" src="https://static.getmonero.org/images/sponsors/jetbrains.png"/>](http://www.jetbrains.com/) -[<img width="150" src="https://static.getmonero.org/images/sponsors/navicat.png"/>](http://www.navicat.com/) -[<img width="150" src="https://static.getmonero.org/images/sponsors/symas.png"/>](http://www.symas.com/) +[<img width="150" src="https://static.getmonero.org/images/sponsors/kitware.png?1"/>](https://kitware.com) +[<img width="100" src="https://static.getmonero.org/images/sponsors/dome9.png"/>](https://dome9.com) +[<img width="150" src="https://static.getmonero.org/images/sponsors/araxis.png"/>](https://araxis.com) +[<img width="150" src="https://static.getmonero.org/images/sponsors/jetbrains.png"/>](https://www.jetbrains.com/) +[<img width="150" src="https://static.getmonero.org/images/sponsors/navicat.png"/>](https://www.navicat.com/) +[<img width="150" src="https://static.getmonero.org/images/sponsors/symas.png"/>](https://www.symas.com/) There are also several mining pools that kindly donate a portion of their fees, [a list of them can be found on our Bitcointalk post](https://bitcointalk.org/index.php?topic=583449.0). @@ -139,7 +139,6 @@ library archives (`.a`). | libzmq | 3.0.0 | NO | `libzmq3-dev` | `zeromq` | `cppzmq-devel` | NO | ZeroMQ library | | libunbound | 1.4.16 | YES | `libunbound-dev` | `unbound` | `unbound-devel` | NO | DNS resolver | | libsodium | ? | NO | `libsodium-dev` | ? | `libsodium-devel` | NO | libsodium | -| libminiupnpc | 2.0 | YES | `libminiupnpc-dev` | `miniupnpc` | `miniupnpc-devel` | YES | NAT punching | | libunwind | any | NO | `libunwind8-dev` | `libunwind` | `libunwind-devel` | YES | Stack traces | | liblzma | any | NO | `liblzma-dev` | `xz` | `xz-devel` | YES | For libunwind | | libreadline | 6.3.0 | NO | `libreadline6-dev` | `readline` | `readline-devel` | YES | Input editing | @@ -155,7 +154,7 @@ library archives (`.a`). build the library binary manually. This can be done with the following command ```sudo apt-get install libgtest-dev && cd /usr/src/gtest && sudo cmake . && sudo make && sudo mv libg* /usr/lib/ ``` Debian / Ubuntu one liner for all dependencies -``` sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libminiupnpc-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpcsclite-dev ``` +``` sudo apt update && sudo apt install build-essential cmake pkg-config libboost-all-dev libssl-dev libzmq3-dev libunbound-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libldns-dev libexpat1-dev doxygen graphviz libpcsclite-dev ``` ### Cloning the repository @@ -291,14 +290,14 @@ If you are using the older Raspbian Jessie image, compiling Monero is a bit more #### On Windows: Binaries for Windows are built on Windows using the MinGW toolchain within -[MSYS2 environment](http://msys2.github.io). The MSYS2 environment emulates a +[MSYS2 environment](https://www.msys2.org). The MSYS2 environment emulates a POSIX system. The toolchain runs within the environment and *cross-compiles* binaries that can run outside of the environment as a regular Windows application. **Preparing the build environment** -* Download and install the [MSYS2 installer](http://msys2.github.io), either the 64-bit or the 32-bit package, depending on your system. +* Download and install the [MSYS2 installer](https://www.msys2.org), either the 64-bit or the 32-bit package, depending on your system. * Open the MSYS shell via the `MSYS2 Shell` shortcut * Update packages using pacman: @@ -373,7 +372,7 @@ We expect to add Monero into the ports tree in the near future, which will aid i This has been tested on OpenBSD 5.8. -You will need to add a few packages to your system. `pkg_add db cmake gcc gcc-libs g++ miniupnpc gtest`. +You will need to add a few packages to your system. `pkg_add db cmake gcc gcc-libs g++ gtest`. The doxygen and graphviz packages are optional and require the xbase set. @@ -386,7 +385,7 @@ To build: `env CC=egcc CXX=eg++ CPP=ecpp DEVELOPER_LOCAL_TOOLS=1 BOOST_ROOT=/pat #### OpenBSD >= 6.2 -You will need to add a few packages to your system. `pkg_add cmake miniupnpc zeromq libiconv`. +You will need to add a few packages to your system. `pkg_add cmake zeromq libiconv`. The doxygen and graphviz packages are optional and require the xbase set. diff --git a/cmake/Doxyfile.in b/cmake/Doxyfile.in index 35a4911f8..81199d5e4 100644 --- a/cmake/Doxyfile.in +++ b/cmake/Doxyfile.in @@ -18,7 +18,7 @@ # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. +# https://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 @@ -242,7 +242,7 @@ EXTENSION_MAPPING = # If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all # comments according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you # can mix doxygen, HTML, and XML commands with Markdown formatting. # Disable only in case of backward compatibilities issues. @@ -589,7 +589,7 @@ LAYOUT_FILE = # containing the references data. This must be a list of .bib files. The # .bib extension is automatically appended if omitted. Using this command # requires the bibtex tool to be installed. See also -# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# https://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style # of the bibliography can be controlled using LATEX_BIB_STYLE. To use this # feature you need bibtex and perl available in the search path. @@ -665,7 +665,7 @@ INPUT = ../README.md \ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# into libc) for the transcoding. See https://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 @@ -833,7 +833,7 @@ REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# tagging system (see https://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO @@ -928,7 +928,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the style sheet and background images # according to this color. Hue is specified as an angle on a colorwheel, -# see http://en.wikipedia.org/wiki/Hue for more information. +# see https://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. @@ -981,7 +981,7 @@ HTML_INDEX_NUM_ENTRIES = 100 # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. -# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO @@ -1179,7 +1179,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax -# (see http://www.mathjax.org) which uses client side Javascript for the +# (see https://www.mathjax.org) which uses client side Javascript for the # rendering instead of using prerendered bitmaps. Use this if you do not # have LaTeX installed or if you want to formulas look prettier in the HTML # output. When enabled you may also need to install MathJax separately and @@ -1194,9 +1194,9 @@ USE_MATHJAX = NO # MATHJAX_RELPATH should be ../mathjax. The default value points to # the MathJax Content Delivery Network so you can quickly see the result without # installing MathJax. However, it is strongly recommended to install a local -# copy of MathJax from http://www.mathjax.org before deployment. +# copy of MathJax from https://www.mathjax.org before deployment. -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension # names that should be enabled during MathJax rendering. @@ -1318,7 +1318,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See -# http://en.wikipedia.org/wiki/BibTeX for more info. +# https://en.wikipedia.org/wiki/BibTeX for more info. LATEX_BIB_STYLE = plain diff --git a/contrib/epee/include/net/http_protocol_handler.inl b/contrib/epee/include/net/http_protocol_handler.inl index 0bdba0bfe..76db5346f 100644 --- a/contrib/epee/include/net/http_protocol_handler.inl +++ b/contrib/epee/include/net/http_protocol_handler.inl @@ -328,8 +328,10 @@ namespace net_utils inline bool analize_http_method(const boost::smatch& result, http::http_method& method, int& http_ver_major, int& http_ver_minor) { CHECK_AND_ASSERT_MES(result[0].matched, false, "simple_http_connection_handler::analize_http_method() assert failed..."); - http_ver_major = boost::lexical_cast<int>(result[11]); - http_ver_minor = boost::lexical_cast<int>(result[12]); + if (!boost::conversion::try_lexical_convert<int>(result[11], http_ver_major)) + return false; + if (!boost::conversion::try_lexical_convert<int>(result[12], http_ver_minor)) + return false; if(result[3].matched) method = http::http_method_options; @@ -351,13 +353,18 @@ namespace net_utils template<class t_connection_context> bool simple_http_connection_handler<t_connection_context>::handle_invoke_query_line() { - STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+).(\\d+))\r?\n", boost::regex::icase | boost::regex::normal); + STATIC_REGEXP_EXPR_1(rexp_match_command_line, "^(((OPTIONS)|(GET)|(HEAD)|(POST)|(PUT)|(DELETE)|(TRACE)) (\\S+) HTTP/(\\d+)\\.(\\d+))\r?\n", boost::regex::icase | boost::regex::normal); // 123 4 5 6 7 8 9 10 11 12 //size_t match_len = 0; boost::smatch result; if(boost::regex_search(m_cache, result, rexp_match_command_line, boost::match_default) && result[0].matched) { - analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi); + if (!analize_http_method(result, m_query_info.m_http_method, m_query_info.m_http_ver_hi, m_query_info.m_http_ver_hi)) + { + m_state = http_state_error; + MERROR("Failed to analyze method"); + return false; + } m_query_info.m_URI = result[10]; if (!parse_uri(m_query_info.m_URI, m_query_info.m_uri_content)) { @@ -554,7 +561,8 @@ namespace net_utils if(!(boost::regex_search( str, result, rexp_mach_field, boost::match_default) && result[0].matched)) return false; - len = boost::lexical_cast<size_t>(result[0]); + try { len = boost::lexical_cast<size_t>(result[0]); } + catch(...) { return false; } return true; } //----------------------------------------------------------------------------------- diff --git a/contrib/epee/src/memwipe.c b/contrib/epee/src/memwipe.c index e3a2f76c8..c2a26c392 100644 --- a/contrib/epee/src/memwipe.c +++ b/contrib/epee/src/memwipe.c @@ -50,7 +50,7 @@ void *memwipe(void *ptr, size_t n) { - if (memset_s(ptr, n, 0, n)) + if (n > 0 && memset_s(ptr, n, 0, n)) { #ifdef NDEBUG fprintf(stderr, "Error: memset_s failed\n"); @@ -67,7 +67,8 @@ void *memwipe(void *ptr, size_t n) void *memwipe(void *ptr, size_t n) { - explicit_bzero(ptr, n); + if (n > 0) + explicit_bzero(ptr, n); SCARECROW return ptr; } @@ -105,7 +106,8 @@ static void memory_cleanse(void *ptr, size_t len) void *memwipe(void *ptr, size_t n) { - memory_cleanse(ptr, n); + if (n > 0) + memory_cleanse(ptr, n); SCARECROW return ptr; } diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index e1b76ec1e..f827ab7c3 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -1213,6 +1213,11 @@ std::vector<std::string> BlockchainBDB::get_filenames() const return full_paths; } +bool BlockchainBDB::remove_data_file(const std::string& folder) +{ + return true; +} + std::string BlockchainBDB::get_db_name() const { LOG_PRINT_L3("BlockchainBDB::" << __func__); diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h index cecbba28f..c90d030a2 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ b/src/blockchain_db/berkeleydb/db_bdb.h @@ -244,6 +244,8 @@ public: virtual std::vector<std::string> get_filenames() const; + virtual bool remove_data_file(const std::string& folder); + virtual std::string get_db_name() const; virtual bool lock(); diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 88ac34255..8544cc3f0 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -218,13 +218,22 @@ uint64_t BlockchainDB::add_block( const block& blk // call out to add the transactions time1 = epee::misc_utils::get_tick_count(); + + uint64_t num_rct_outs = 0; add_transaction(blk_hash, blk.miner_tx); + if (blk.miner_tx.version == 2) + num_rct_outs += blk.miner_tx.vout.size(); int tx_i = 0; crypto::hash tx_hash = crypto::null_hash; for (const transaction& tx : txs) { tx_hash = blk.tx_hashes[tx_i]; add_transaction(blk_hash, tx, &tx_hash); + for (const auto &vout: tx.vout) + { + if (vout.amount == 0) + ++num_rct_outs; + } ++tx_i; } TIME_MEASURE_FINISH(time1); @@ -232,7 +241,7 @@ uint64_t BlockchainDB::add_block( const block& blk // call out to subclass implementation to add the block & metadata time1 = epee::misc_utils::get_tick_count(); - add_block(blk, block_size, cumulative_difficulty, coins_generated, blk_hash); + add_block(blk, block_size, cumulative_difficulty, coins_generated, num_rct_outs, blk_hash); TIME_MEASURE_FINISH(time1); time_add_block1 += time1; diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 564016fc9..6851e2404 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -367,6 +367,7 @@ private: , const size_t& block_size , const difficulty_type& cumulative_difficulty , const uint64_t& coins_generated + , uint64_t num_rct_outs , const crypto::hash& blk_hash ) = 0; @@ -655,6 +656,20 @@ public: */ virtual std::vector<std::string> get_filenames() const = 0; + /** + * @brief remove file(s) storing the database + * + * This function is for resetting the database (for core tests, functional tests, etc). + * The function reset() is not usable because it needs to open the database file first + * which can fail if the existing database file is in an incompatible format. + * As such, this function needs to be called before calling open(). + * + * @param folder The path of the folder containing the database file(s) which must not end with slash '/'. + * + * @return true if the operation is succesfull + */ + virtual bool remove_data_file(const std::string& folder) const = 0; + // return the name of the folder the db's file(s) should reside in /** * @brief gets the name of the folder the BlockchainDB's file(s) should be in @@ -892,6 +907,20 @@ public: virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0; /** + * @brief fetch a block's cumulative number of rct outputs + * + * The subclass should return the numer of rct outputs in the blockchain + * up to the block with the given height (inclusive). + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the cumulative number of rct outputs + */ + virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const = 0; + + /** * @brief fetch the top block's timestamp * * The subclass should return the timestamp of the most recent block. @@ -1536,6 +1565,13 @@ public: */ virtual bool is_read_only() const = 0; + /** + * @brief get disk space requirements + * + * @return the size required + */ + virtual uint64_t get_database_size() const = 0; + // TODO: this should perhaps be (or call) a series of functions which // progressively update through version updates /** diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 367bfa49e..a6eb3d880 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -35,6 +35,7 @@ #include <random> #include "string_tools.h" +#include "file_io_utils.h" #include "common/util.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "crypto/crypto.h" @@ -53,7 +54,7 @@ using epee::string_tools::pod_to_hex; using namespace crypto; // Increase when the DB structure changes -#define VERSION 2 +#define VERSION 3 namespace { @@ -250,6 +251,16 @@ inline void lmdb_db_open(MDB_txn* txn, const char* name, int flags, MDB_dbi& dbi namespace cryptonote { +typedef struct mdb_block_info_old +{ + uint64_t bi_height; + uint64_t bi_timestamp; + uint64_t bi_coins; + uint64_t bi_size; // a size_t really but we need 32-bit compat + difficulty_type bi_diff; + crypto::hash bi_hash; +} mdb_block_info_old; + typedef struct mdb_block_info { uint64_t bi_height; @@ -258,6 +269,7 @@ typedef struct mdb_block_info uint64_t bi_size; // a size_t really but we need 32-bit compat difficulty_type bi_diff; crypto::hash bi_hash; + uint64_t bi_cum_rct; } mdb_block_info; typedef struct blk_height { @@ -667,7 +679,7 @@ estim: } void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, - const crypto::hash& blk_hash) + uint64_t num_rct_outs, const crypto::hash& blk_hash) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -715,6 +727,16 @@ void BlockchainLMDB::add_block(const block& blk, const size_t& block_size, const bi.bi_size = block_size; bi.bi_diff = cumulative_difficulty; bi.bi_hash = blk_hash; + bi.bi_cum_rct = num_rct_outs; + if (blk.major_version >= 4) + { + uint64_t last_height = m_height-1; + MDB_val_set(h, last_height); + if ((result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &h, MDB_GET_BOTH))) + throw1(BLOCK_DNE(lmdb_error("Failed to get block info: ", result).c_str())); + const mdb_block_info *bi_prev = (const mdb_block_info*)h.mv_data; + bi.bi_cum_rct += bi_prev->bi_cum_rct; + } MDB_val_set(val, bi); result = mdb_cursor_put(m_cur_block_info, (MDB_val *)&zerokval, &val, MDB_APPENDDUP); @@ -759,8 +781,6 @@ void BlockchainLMDB::remove_block() if ((result = mdb_cursor_del(m_cur_block_heights, 0))) throw1(DB_ERROR(lmdb_error("Failed to add removal of block height by hash to db transaction: ", result).c_str())); - if ((result = mdb_cursor_get(m_cur_blocks, &k, NULL, MDB_SET))) - throw1(DB_ERROR(lmdb_error("Failed to locate block for removal: ", result).c_str())); if ((result = mdb_cursor_del(m_cur_blocks, 0))) throw1(DB_ERROR(lmdb_error("Failed to add removal of block to db transaction: ", result).c_str())); @@ -1143,6 +1163,8 @@ BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB() m_cum_size = 0; m_cum_count = 0; + // reset may also need changing when initialize things here + m_hardfork = nullptr; } @@ -1391,6 +1413,9 @@ void BlockchainLMDB::sync() LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); + if (is_read_only()) + return; + // Does nothing unless LMDB environment was opened with MDB_NOSYNC or in part // MDB_NOMETASYNC. Force flush to be synchronous. if (auto result = mdb_env_sync(m_env, true)) @@ -1469,6 +1494,21 @@ std::vector<std::string> BlockchainLMDB::get_filenames() const return filenames; } +bool BlockchainLMDB::remove_data_file(const std::string& folder) const +{ + const std::string filename = folder + "/data.mdb"; + try + { + boost::filesystem::remove(filename); + } + catch (const std::exception &e) + { + MERROR("Failed to remove " << filename << ": " << e.what()); + return false; + } + return true; +} + std::string BlockchainLMDB::get_db_name() const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -1908,6 +1948,43 @@ uint64_t BlockchainLMDB::get_block_timestamp(const uint64_t& height) const return ret; } +std::vector<uint64_t> BlockchainLMDB::get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + std::vector<uint64_t> res; + int result; + + if (heights.empty()) + return {}; + res.reserve(heights.size()); + + TXN_PREFIX_RDONLY(); + RCURSOR(block_info); + + MDB_stat db_stats; + if ((result = mdb_stat(m_txn, m_blocks, &db_stats))) + throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str())); + for (size_t i = 0; i < heights.size(); ++i) + if (heights[i] >= db_stats.ms_entries) + throw0(BLOCK_DNE(std::string("Attempt to get rct distribution from height " + std::to_string(heights[i]) + " failed -- block size not in db").c_str())); + + MDB_val v; + + for (uint64_t height: heights) + { + MDB_val_set(v, height); + result = mdb_cursor_get(m_cur_block_info, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); + if (result) + throw0(DB_ERROR(lmdb_error("Error attempting to retrieve rct distribution from the db: ", result).c_str())); + const mdb_block_info *bi = (const mdb_block_info *)v.mv_data; + res.push_back(bi->bi_cum_rct); + } + + TXN_POSTFIX_RDONLY(); + return res; +} + uint64_t BlockchainLMDB::get_top_block_timestamp() const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -3328,6 +3405,7 @@ bool BlockchainLMDB::get_output_distribution(uint64_t amount, uint64_t from_heig MDB_val_set(k, amount); MDB_val v; MDB_cursor_op op = MDB_SET; + base = 0; while (1) { int ret = mdb_cursor_get(m_cur_output_amounts, &k, &v, op); @@ -3346,6 +3424,9 @@ bool BlockchainLMDB::get_output_distribution(uint64_t amount, uint64_t from_heig break; } + for (size_t n = 1; n < distribution.size(); ++n) + distribution[n] += distribution[n - 1]; + TXN_POSTFIX_RDONLY(); return true; @@ -3423,6 +3504,16 @@ bool BlockchainLMDB::is_read_only() const return false; } +uint64_t BlockchainLMDB::get_database_size() const +{ + uint64_t size = 0; + boost::filesystem::path datafile(m_folder); + datafile /= CRYPTONOTE_BLOCKCHAINDATA_FILENAME; + if (!epee::file_io_utils::get_file_size(datafile.string(), size)) + size = 0; + return size; +} + void BlockchainLMDB::fixup() { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -3440,7 +3531,7 @@ void BlockchainLMDB::fixup() if (result) \ throw0(DB_ERROR(lmdb_error("Failed to get DB record for " name ": ", result).c_str())); \ ptr = (char *)k.mv_data; \ - ptr[sizeof(name)-2] = 's' + ptr[sizeof(name)-2]++ #define LOGIF(y) if (ELPP->vRegistry()->allowed(y, "global")) @@ -3580,7 +3671,7 @@ void BlockchainLMDB::migrate_0_1() break; } MDB_dbi diffs, hashes, sizes, timestamps; - mdb_block_info bi; + mdb_block_info_old bi; MDB_val_set(nv, bi); lmdb_db_open(txn, "block_diffs", 0, diffs, "Failed to open db handle for block_diffs"); @@ -4120,6 +4211,141 @@ void BlockchainLMDB::migrate_1_2() txn.commit(); } +void BlockchainLMDB::migrate_2_3() +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + uint64_t i; + int result; + mdb_txn_safe txn(false); + MDB_val k, v; + char *ptr; + + MGINFO_YELLOW("Migrating blockchain from DB version 2 to 3 - this may take a while:"); + + do { + LOG_PRINT_L1("migrating block info:"); + + result = mdb_txn_begin(m_env, NULL, 0, txn); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + + MDB_stat db_stats; + if ((result = mdb_stat(txn, m_blocks, &db_stats))) + throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str())); + const uint64_t blockchain_height = db_stats.ms_entries; + + MDEBUG("enumerating rct outputs..."); + std::vector<uint64_t> distribution(blockchain_height, 0); + bool r = for_all_outputs(0, [&](uint64_t height) { + if (height >= blockchain_height) + { + MERROR("Output found claiming height >= blockchain height"); + return false; + } + distribution[height]++; + return true; + }); + if (!r) + throw0(DB_ERROR("Failed to build rct output distribution")); + for (size_t i = 1; i < distribution.size(); ++i) + distribution[i] += distribution[i - 1]; + + /* the block_info table name is the same but the old version and new version + * have incompatible data. Create a new table. We want the name to be similar + * to the old name so that it will occupy the same location in the DB. + */ + MDB_dbi o_block_info = m_block_info; + lmdb_db_open(txn, "block_infn", MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_info, "Failed to open db handle for block_infn"); + mdb_set_dupsort(txn, m_block_info, compare_uint64); + + MDB_cursor *c_old, *c_cur; + i = 0; + while(1) { + if (!(i % 1000)) { + if (i) { + LOGIF(el::Level::Info) { + std::cout << i << " / " << blockchain_height << " \r" << std::flush; + } + txn.commit(); + result = mdb_txn_begin(m_env, NULL, 0, txn); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + } + result = mdb_cursor_open(txn, m_block_info, &c_cur); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_infn: ", result).c_str())); + result = mdb_cursor_open(txn, o_block_info, &c_old); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_info: ", result).c_str())); + if (!i) { + MDB_stat db_stat; + result = mdb_stat(txn, m_block_info, &db_stats); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to query m_block_info: ", result).c_str())); + i = db_stats.ms_entries; + } + } + result = mdb_cursor_get(c_old, &k, &v, MDB_NEXT); + if (result == MDB_NOTFOUND) { + txn.commit(); + break; + } + else if (result) + throw0(DB_ERROR(lmdb_error("Failed to get a record from block_info: ", result).c_str())); + const mdb_block_info_old *bi_old = (const mdb_block_info_old*)v.mv_data; + mdb_block_info bi; + bi.bi_height = bi_old->bi_height; + bi.bi_timestamp = bi_old->bi_timestamp; + bi.bi_coins = bi_old->bi_coins; + bi.bi_size = bi_old->bi_size; + bi.bi_diff = bi_old->bi_diff; + bi.bi_hash = bi_old->bi_hash; + if (bi_old->bi_height >= distribution.size()) + throw0(DB_ERROR("Bad height in block_info record")); + bi.bi_cum_rct = distribution[bi_old->bi_height]; + MDB_val_set(nv, bi); + result = mdb_cursor_put(c_cur, (MDB_val *)&zerokval, &nv, MDB_APPENDDUP); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to put a record into block_infn: ", result).c_str())); + /* we delete the old records immediately, so the overall DB and mapsize should not grow. + * This is a little slower than just letting mdb_drop() delete it all at the end, but + * it saves a significant amount of disk space. + */ + result = mdb_cursor_del(c_old, 0); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_info: ", result).c_str())); + i++; + } + + result = mdb_txn_begin(m_env, NULL, 0, txn); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + /* Delete the old table */ + result = mdb_drop(txn, o_block_info, 1); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to delete old block_info table: ", result).c_str())); + + RENAME_DB("block_infn"); + + lmdb_db_open(txn, "block_info", MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_info, "Failed to open db handle for block_infn"); + mdb_set_dupsort(txn, m_block_info, compare_uint64); + + txn.commit(); + } while(0); + + uint32_t version = 3; + v.mv_data = (void *)&version; + v.mv_size = sizeof(version); + MDB_val_copy<const char *> vk("version"); + result = mdb_txn_begin(m_env, NULL, 0, txn); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + result = mdb_put(txn, m_properties, &vk, &v, 0); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str())); + txn.commit(); +} + void BlockchainLMDB::migrate(const uint32_t oldversion) { switch(oldversion) { @@ -4127,6 +4353,8 @@ void BlockchainLMDB::migrate(const uint32_t oldversion) migrate_0_1(); /* FALLTHRU */ case 1: migrate_1_2(); /* FALLTHRU */ + case 2: + migrate_2_3(); /* FALLTHRU */ default: ; } diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index cc1b06ca0..8b214d2df 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -166,7 +166,7 @@ struct mdb_txn_safe class BlockchainLMDB : public BlockchainDB { public: - BlockchainLMDB(bool batch_transactions=false); + BlockchainLMDB(bool batch_transactions=true); ~BlockchainLMDB(); virtual void open(const std::string& filename, const int mdb_flags=0); @@ -181,6 +181,8 @@ public: virtual std::vector<std::string> get_filenames() const; + virtual bool remove_data_file(const std::string& folder) const; + virtual std::string get_db_name() const; virtual bool lock(); @@ -197,6 +199,8 @@ public: virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const; + virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const; + virtual uint64_t get_block_timestamp(const uint64_t& height) const; virtual uint64_t get_top_block_timestamp() const; @@ -317,6 +321,7 @@ private: , const size_t& block_size , const difficulty_type& cumulative_difficulty , const uint64_t& coins_generated + , uint64_t num_rct_outs , const crypto::hash& block_hash ); @@ -375,6 +380,8 @@ private: virtual bool is_read_only() const; + virtual uint64_t get_database_size() const; + // fix up anything that may be wrong due to past bugs virtual void fixup(); @@ -387,6 +394,9 @@ private: // migrate from DB version 1 to 2 void migrate_1_2(); + // migrate from DB version 2 to 3 + void migrate_2_3(); + void cleanup_batch(); private: diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index c76641598..7291dbd68 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -33,6 +33,7 @@ #include <boost/filesystem.hpp> #include <boost/algorithm/string.hpp> +#include <unistd.h> #include "misc_log_ex.h" #include "bootstrap_file.h" #include "bootstrap_serialization.h" diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index aa85e5e53..ba2697226 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -400,18 +400,18 @@ uint64_t BootstrapFile::count_bytes(std::ifstream& import_file, uint64_t blocks, { std::cout << refresh_string; MWARNING("WARNING: chunk_size " << chunk_size << " > BUFFER_SIZE " << BUFFER_SIZE - << " height: " << h-1); + << " height: " << h-1 << ", offset " << bytes_read); throw std::runtime_error("Aborting: chunk size exceeds buffer size"); } if (chunk_size > CHUNK_SIZE_WARNING_THRESHOLD) { std::cout << refresh_string; MDEBUG("NOTE: chunk_size " << chunk_size << " > " << CHUNK_SIZE_WARNING_THRESHOLD << " << height: " - << h-1); + << h-1 << ", offset " << bytes_read); } else if (chunk_size <= 0) { std::cout << refresh_string; - MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1); + MDEBUG("ERROR: chunk_size " << chunk_size << " <= 0" << " height: " << h-1 << ", offset " << bytes_read); throw std::runtime_error("Aborting"); } // skip to next expected block size value diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 808ef7630..f0df05b0d 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -78,7 +78,6 @@ monero_add_library(common DEPENDS generate_translations_header) target_link_libraries(common PUBLIC - epee cncrypto ${UNBOUND_LIBRARY} ${LIBUNWIND_LIBRARIES} diff --git a/src/common/scoped_message_writer.h b/src/common/scoped_message_writer.h index d7517babb..d887a13c9 100644 --- a/src/common/scoped_message_writer.h +++ b/src/common/scoped_message_writer.h @@ -73,7 +73,7 @@ public: #if defined(_MSC_VER) , m_oss(std::move(rhs.m_oss)) #else - // GCC bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316 + // GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54316 , m_oss(rhs.m_oss.str(), std::ios_base::out | std::ios_base::ate) #endif , m_color(std::move(rhs.m_color)) diff --git a/src/common/stack_trace.cpp b/src/common/stack_trace.cpp index 9c2bf4b53..d6dc4d7cc 100644 --- a/src/common/stack_trace.cpp +++ b/src/common/stack_trace.cpp @@ -51,7 +51,7 @@ #define ST_LOG(x) CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,MONERO_DEFAULT_LOG_CATEGORY) << x -// from http://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c +// from https://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c // The decl of __cxa_throw in /usr/include/.../cxxabi.h uses // 'std::type_info *', but GCC's built-in protype uses 'void *'. diff --git a/src/common/util.cpp b/src/common/util.cpp index 7d9d7b408..f644c573c 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -919,4 +919,23 @@ std::string get_nix_version_display_string() return {}; } } + + std::string glob_to_regex(const std::string &val) + { + std::string newval; + + bool escape = false; + for (char c: val) + { + if (c == '*') + newval += escape ? "*" : ".*"; + else if (c == '?') + newval += escape ? "?" : "."; + else if (c == '\\') + newval += '\\', escape = !escape; + else + newval += c; + } + return newval; + } } diff --git a/src/common/util.h b/src/common/util.h index a57a85fee..6ec901e7f 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -231,4 +231,6 @@ namespace tools bool is_hdd(const char *path); boost::optional<std::pair<uint32_t, uint32_t>> parse_subaddress_lookahead(const std::string& str); + + std::string glob_to_regex(const std::string &val); } diff --git a/src/crypto/blake256.c b/src/crypto/blake256.c index d503c47e0..6ef7d4207 100644 --- a/src/crypto/blake256.c +++ b/src/crypto/blake256.c @@ -31,7 +31,7 @@ * The blake256_* and blake224_* functions are largely copied from * blake256_light.c and blake224_light.c from the BLAKE website: * - * http://131002.net/blake/ + * https://131002.net/blake/ * * The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224. * HMAC is specified by RFC 2104. diff --git a/src/crypto/chacha.h b/src/crypto/chacha.h index 2b3ed8043..1dc270faf 100644 --- a/src/crypto/chacha.h +++ b/src/crypto/chacha.h @@ -69,22 +69,26 @@ namespace crypto { chacha20(data, length, key.data(), reinterpret_cast<const uint8_t*>(&iv), cipher); } - inline void generate_chacha_key(const void *data, size_t size, chacha_key& key) { + inline void generate_chacha_key(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); + for (uint64_t n = 1; n < kdf_rounds; ++n) + crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); memcpy(&unwrap(key), pwd_hash.data(), sizeof(key)); } - inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key) { + inline void generate_chacha_key_prehashed(const void *data, size_t size, chacha_key& key, uint64_t kdf_rounds) { static_assert(sizeof(chacha_key) <= sizeof(hash), "Size of hash must be at least that of chacha_key"); tools::scrubbed_arr<char, HASH_SIZE> pwd_hash; crypto::cn_slow_hash(data, size, pwd_hash.data(), 0/*variant*/, 1/*prehashed*/); + for (uint64_t n = 1; n < kdf_rounds; ++n) + crypto::cn_slow_hash(pwd_hash.data(), pwd_hash.size(), pwd_hash.data(), 0/*variant*/, 0/*prehashed*/); memcpy(&unwrap(key), pwd_hash.data(), sizeof(key)); } - inline void generate_chacha_key(std::string password, chacha_key& key) { - return generate_chacha_key(password.data(), password.size(), key); + inline void generate_chacha_key(std::string password, chacha_key& key, uint64_t kdf_rounds) { + return generate_chacha_key(password.data(), password.size(), key, kdf_rounds); } } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index f4ef751d3..0c019938d 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -93,18 +93,32 @@ namespace crypto { generate_random_bytes_not_thread_safe(N, bytes); } - /* generate a random 32-byte (256-bit) integer and copy it to res */ - static inline void random_scalar_not_thread_safe(ec_scalar &res) { - unsigned char tmp[64]; - generate_random_bytes_not_thread_safe(64, tmp); - sc_reduce(tmp); - memcpy(&res, tmp, 32); + static inline bool less32(const unsigned char *k0, const unsigned char *k1) + { + for (int n = 31; n >= 0; --n) + { + if (k0[n] < k1[n]) + return true; + if (k0[n] > k1[n]) + return false; + } + return false; } + + void random32_unbiased(unsigned char *bytes) + { + // l = 2^252 + 27742317777372353535851937790883648493. + // it fits 15 in 32 bytes + static const unsigned char limit[32] = { 0xe3, 0x6a, 0x67, 0x72, 0x8b, 0xce, 0x13, 0x29, 0x8f, 0x30, 0x82, 0x8c, 0x0b, 0xa4, 0x10, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0 }; + do + { + generate_random_bytes_thread_safe(32, bytes); + } while (!less32(bytes, limit)); // should be good about 15/16 of the time + sc_reduce32(bytes); + } + /* generate a random 32-byte (256-bit) integer and copy it to res */ static inline void random_scalar(ec_scalar &res) { - unsigned char tmp[64]; - generate_random_bytes_thread_safe(64, tmp); - sc_reduce(tmp); - memcpy(&res, tmp, 32); + random32_unbiased((unsigned char*)res.data); } void hash_to_scalar(const void *data, size_t length, ec_scalar &res) { diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 9ea0f2ec0..449af8f6d 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -99,6 +99,7 @@ namespace crypto { #pragma pack(pop) void hash_to_scalar(const void *data, size_t length, ec_scalar &res); + void random32_unbiased(unsigned char *bytes); static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 && sizeof(public_key) == 32 && sizeof(secret_key) == 32 && diff --git a/src/crypto/crypto_ops_builder/ref10/README.md b/src/crypto/crypto_ops_builder/ref10/README.md new file mode 100644 index 000000000..59193305b --- /dev/null +++ b/src/crypto/crypto_ops_builder/ref10/README.md @@ -0,0 +1,4 @@ +This code comes from Daniel J. Bernstein's SUPERCOP source, +released in the public domain. + +[http://ed25519.cr.yp.to/software.html](http://ed25519.cr.yp.to/software.html) diff --git a/src/crypto/crypto_ops_builder/ref10/description b/src/crypto/crypto_ops_builder/ref10/description index cbfcb2cba..99f747747 100644 --- a/src/crypto/crypto_ops_builder/ref10/description +++ b/src/crypto/crypto_ops_builder/ref10/description @@ -1,2 +1,2 @@ EdDSA signatures using Curve25519 -from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2 +from https://hyperelliptic.org/ebats/supercop-20141124.tar.bz2 diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py index 9b55d260d..0ed97d5f4 100644 --- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py +++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/MakeCryptoOps.py @@ -1,5 +1,5 @@ #assumes you have gnu sed, osx sed might need slight syntax changeo -#c.f. http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files +#c.f. https://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files #written by shen-noether monero research labs @@ -8,7 +8,7 @@ import glob #for copy files import textwrap #for comments etc print("make sure you have cat and grep installed") -print("also assumes gnu sed syntax, c.f. :http://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files") +print("also assumes gnu sed syntax, c.f. :https://unix.stackexchange.com/questions/112023/how-can-i-replace-a-string-in-a-files") print("I believe osx may have slightly different version of sed") print("maybe someone smart can replace the sed with perl..") diff --git a/src/crypto/crypto_ops_builder/ref10CommentedCombined/description b/src/crypto/crypto_ops_builder/ref10CommentedCombined/description index fadc9f9af..9407b400a 100644 --- a/src/crypto/crypto_ops_builder/ref10CommentedCombined/description +++ b/src/crypto/crypto_ops_builder/ref10CommentedCombined/description @@ -2,6 +2,6 @@ shen_ed25519_ref10 MakeCryptoOps.py makes crypto-ops.c in the Monero source from the ref10 implementation EdDSA signatures using Curve25519 -from http://hyperelliptic.org/ebats/supercop-20141124.tar.bz2 +from https://hyperelliptic.org/ebats/supercop-20141124.tar.bz2 Commented / combined by Shen Noether, Monero Research Lab diff --git a/src/crypto/initializer.h b/src/crypto/initializer.h index afbace726..107988d2b 100644 --- a/src/crypto/initializer.h +++ b/src/crypto/initializer.h @@ -43,8 +43,8 @@ #elif defined(_MSC_VER) #include <assert.h> #include <stdlib.h> -// http://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc -// http://msdn.microsoft.com/en-us/library/bb918180.aspx +// https://stackoverflow.com/questions/1113409/attribute-constructor-equivalent-in-vc +// https://msdn.microsoft.com/en-us/library/bb918180.aspx #pragma section(".CRT$XCT", read) #define INITIALIZER(name) \ static void __cdecl name(void); \ diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 35e98f2f5..9d4fc0dfa 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -309,7 +309,7 @@ STATIC INLINE void aes_256_assist2(__m128i* t1, __m128i * t3) * CPU AES support. * For more information about these functions, see page 19 of Intel's AES instructions * white paper: - * http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/aes-instructions-set-white-paper.pdf + * https://www.intel.com/content/dam/doc/white-paper/advanced-encryption-standard-new-instructions-set-paper.pdf * * @param key the input 128 bit key * @param expandedKey An output buffer to hold the generated key schedule @@ -558,7 +558,7 @@ void slow_hash_free_state(void) * AES support on x86 CPUs. * * A diagram of the inner loop of this function can be found at - * http://www.cs.cmu.edu/~dga/crypto/xmr/cryptonight.png + * https://www.cs.cmu.edu/~dga/crypto/xmr/cryptonight.png * * @param data the data to hash * @param length the length in bytes of the data diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c index e6d6a267c..57c38b86b 100644 --- a/src/crypto/tree-hash.c +++ b/src/crypto/tree-hash.c @@ -67,7 +67,7 @@ size_t tree_hash_cnt(size_t count) { } void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { -// The blockchain block at height 202612 http://monerochain.info/block/bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698 +// The blockchain block at height 202612 https://moneroblocks.info/block/202612 // contained 514 transactions, that triggered bad calculation of variable "cnt" in the original version of this function // as from CryptoNote code. // diff --git a/src/cryptonote_basic/hardfork.h b/src/cryptonote_basic/hardfork.h index ee5ec0596..a63a66976 100644 --- a/src/cryptonote_basic/hardfork.h +++ b/src/cryptonote_basic/hardfork.h @@ -220,6 +220,14 @@ namespace cryptonote */ uint64_t get_window_size() const { return window_size; } + struct Params { + uint8_t version; + uint8_t threshold; + uint64_t height; + time_t time; + Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {} + }; + private: uint8_t get_block_version(uint64_t height) const; @@ -244,13 +252,6 @@ namespace cryptonote uint8_t original_version; uint64_t original_version_till_height; - struct Params { - uint8_t version; - uint8_t threshold; - uint64_t height; - time_t time; - Params(uint8_t version, uint64_t height, uint8_t threshold, time_t time): version(version), threshold(threshold), height(height), time(time) {} - }; std::vector<Params> heights; std::deque<uint8_t> versions; /* rolling window of the last N blocks' versions */ diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index 3a3222f9b..dfe456ef4 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -490,7 +490,7 @@ namespace cryptonote { //we lucky! ++m_config.current_extra_message_index; - MGINFO_GREEN("Found block for difficulty: " << local_diff); + MGINFO_GREEN("Found block " << get_block_hash(b) << " at height " << height << " for difficulty: " << local_diff); if(!m_phandler->handle_block_found(b)) { --m_config.current_extra_message_index; diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 73ce98366..dad30906e 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -330,7 +330,7 @@ uint64_t Blockchain::get_current_blockchain_height() const //------------------------------------------------------------------ //FIXME: possibly move this into the constructor, to avoid accidentally // dereferencing a null BlockchainDB pointer -bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options) +bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline, const cryptonote::test_options *test_options, difficulty_type fixed_difficulty) { LOG_PRINT_L3("Blockchain::" << __func__); CRITICAL_REGION_LOCAL(m_tx_pool); @@ -352,6 +352,7 @@ bool Blockchain::init(BlockchainDB* db, const network_type nettype, bool offline m_nettype = test_options != NULL ? FAKECHAIN : nettype; m_offline = offline; + m_fixed_difficulty = fixed_difficulty; if (m_hardfork == nullptr) { if (m_nettype == FAKECHAIN || m_nettype == STAGENET) @@ -795,6 +796,11 @@ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk, bool *orph // less blocks than desired if there aren't enough. difficulty_type Blockchain::get_difficulty_for_next_block() { + if (m_fixed_difficulty) + { + return m_db->height() ? m_fixed_difficulty : 1; + } + LOG_PRINT_L3("Blockchain::" << __func__); crypto::hash top_hash = get_tail_id(); @@ -1006,6 +1012,11 @@ bool Blockchain::switch_to_alternative_blockchain(std::list<blocks_ext_by_hash:: // an alternate chain. difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list<blocks_ext_by_hash::iterator>& alt_chain, block_extended_info& bei) const { + if (m_fixed_difficulty) + { + return m_db->height() ? m_fixed_difficulty : 1; + } + LOG_PRINT_L3("Blockchain::" << __func__); std::vector<uint64_t> timestamps; std::vector<difficulty_type> cumulative_difficulties; @@ -1985,14 +1996,14 @@ void Blockchain::get_output_key_mask_unlocked(const uint64_t& amount, const uint //------------------------------------------------------------------ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, uint64_t to_height, uint64_t &start_height, std::vector<uint64_t> &distribution, uint64_t &base) const { - // rct outputs don't exist before v3 + // rct outputs don't exist before v4 if (amount == 0) { switch (m_nettype) { - case STAGENET: start_height = stagenet_hard_forks[2].height; break; - case TESTNET: start_height = testnet_hard_forks[2].height; break; - case MAINNET: start_height = mainnet_hard_forks[2].height; break; + case STAGENET: start_height = stagenet_hard_forks[3].height; break; + case TESTNET: start_height = testnet_hard_forks[3].height; break; + case MAINNET: start_height = mainnet_hard_forks[3].height; break; default: return false; } } @@ -2000,11 +2011,40 @@ bool Blockchain::get_output_distribution(uint64_t amount, uint64_t from_height, start_height = 0; base = 0; + if (to_height > 0 && to_height < from_height) + return false; + const uint64_t real_start_height = start_height; if (from_height > start_height) start_height = from_height; - return m_db->get_output_distribution(amount, start_height, to_height, distribution, base); + distribution.clear(); + uint64_t db_height = m_db->height(); + if (db_height == 0) + return false; + if (to_height == 0) + to_height = db_height - 1; + if (start_height >= db_height || to_height >= db_height) + return false; + if (amount == 0) + { + std::vector<uint64_t> heights; + heights.reserve(to_height + 1 - start_height); + uint64_t real_start_height = start_height > 0 ? start_height-1 : start_height; + for (uint64_t h = real_start_height; h <= to_height; ++h) + heights.push_back(h); + distribution = m_db->get_block_cumulative_rct_outputs(heights); + if (start_height > 0) + { + base = distribution[0]; + distribution.erase(distribution.begin()); + } + return true; + } + else + { + return m_db->get_output_distribution(amount, start_height, to_height, distribution, base); + } } //------------------------------------------------------------------ // This function takes a list of block hashes from another node @@ -2217,7 +2257,8 @@ bool Blockchain::find_blockchain_supplement(const std::list<crypto::hash>& qbloc CRITICAL_REGION_LOCAL(m_blockchain_lock); bool result = find_blockchain_supplement(qblock_ids, resp.m_block_ids, resp.start_height, resp.total_height); - resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1); + if (result) + resp.cumulative_difficulty = m_db->get_block_cumulative_difficulty(resp.total_height - 1); return result; } @@ -3323,6 +3364,7 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& if(bl.prev_id != get_tail_id()) { MERROR_VER("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << get_tail_id()); + bvc.m_verifivation_failed = true; leave: m_db->block_txn_stop(); return false; @@ -3624,6 +3666,7 @@ leave: { //TODO: figure out the best way to deal with this failure LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + bvc.m_verifivation_failed = true; return_tx_to_pool(txs); return false; } @@ -3653,6 +3696,7 @@ leave: // appears to be a NOP *and* is called elsewhere. wat? m_tx_pool.on_blockchain_inc(new_height, id); + get_difficulty_for_next_block(); // just to cache it return true; } @@ -4405,6 +4449,39 @@ HardFork::State Blockchain::get_hard_fork_state() const return m_hardfork->get_state(); } +const std::vector<HardFork::Params>& Blockchain::get_hard_fork_heights(network_type nettype) +{ + static const std::vector<HardFork::Params> mainnet_heights = []() + { + std::vector<HardFork::Params> heights; + for (const auto& i : mainnet_hard_forks) + heights.emplace_back(i.version, i.height, i.threshold, i.time); + return heights; + }(); + static const std::vector<HardFork::Params> testnet_heights = []() + { + std::vector<HardFork::Params> heights; + for (const auto& i : testnet_hard_forks) + heights.emplace_back(i.version, i.height, i.threshold, i.time); + return heights; + }(); + static const std::vector<HardFork::Params> stagenet_heights = []() + { + std::vector<HardFork::Params> heights; + for (const auto& i : stagenet_hard_forks) + heights.emplace_back(i.version, i.height, i.threshold, i.time); + return heights; + }(); + static const std::vector<HardFork::Params> dummy; + switch (nettype) + { + case MAINNET: return mainnet_heights; + case TESTNET: return testnet_heights; + case STAGENET: return stagenet_heights; + default: return dummy; + } +} + bool Blockchain::get_hard_fork_voting_info(uint8_t version, uint32_t &window, uint32_t &votes, uint32_t &threshold, uint64_t &earliest_height, uint8_t &voting) const { return m_hardfork->get_voting_info(version, window, votes, threshold, earliest_height, voting); @@ -4420,9 +4497,9 @@ std::map<uint64_t, std::tuple<uint64_t, uint64_t, uint64_t>> Blockchain:: get_ou return m_db->get_output_histogram(amounts, unlocked, recent_cutoff, min_count); } -std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_alternative_chains() const +std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> Blockchain::get_alternative_chains() const { - std::list<std::pair<Blockchain::block_extended_info,uint64_t>> chains; + std::list<std::pair<Blockchain::block_extended_info,std::vector<crypto::hash>>> chains; for (const auto &i: m_alternative_chains) { @@ -4438,15 +4515,16 @@ std::list<std::pair<Blockchain::block_extended_info,uint64_t>> Blockchain::get_a } if (!found) { - uint64_t length = 1; + std::vector<crypto::hash> chain; auto h = i.second.bl.prev_id; + chain.push_back(top); blocks_ext_by_hash::const_iterator prev; while ((prev = m_alternative_chains.find(h)) != m_alternative_chains.end()) { + chain.push_back(h); h = prev->second.bl.prev_id; - ++length; } - chains.push_back(std::make_pair(i.second, length)); + chains.push_back(std::make_pair(i.second, chain)); } } return chains; diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 36d6b8609..d95c8ed15 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -114,10 +114,11 @@ namespace cryptonote * @param nettype network type * @param offline true if running offline, else false * @param test_options test parameters + * @param fixed_difficulty fixed difficulty for testing purposes; 0 means disabled * * @return true on success, false if any initialization steps fail */ - bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL); + bool init(BlockchainDB* db, const network_type nettype = MAINNET, bool offline = false, const cryptonote::test_options *test_options = NULL, difficulty_type fixed_difficulty = 0); /** * @brief Initialize the Blockchain state @@ -755,6 +756,13 @@ namespace cryptonote HardFork::State get_hard_fork_state() const; /** + * @brief gets the hardfork heights of given network + * + * @return the HardFork object + */ + static const std::vector<HardFork::Params>& get_hard_fork_heights(network_type nettype); + + /** * @brief gets the current hardfork version in use/voted for * * @return the version @@ -939,7 +947,7 @@ namespace cryptonote * * @return a list of chains */ - std::list<std::pair<block_extended_info,uint64_t>> get_alternative_chains() const; + std::list<std::pair<block_extended_info,std::vector<crypto::hash>>> get_alternative_chains() const; void add_txpool_tx(transaction &tx, const txpool_tx_meta_t &meta); void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &meta); @@ -1040,6 +1048,7 @@ namespace cryptonote network_type m_nettype; bool m_offline; + difficulty_type m_fixed_difficulty; std::atomic<bool> m_cancel; diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 910bf0c1f..18490c65e 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -76,6 +76,16 @@ namespace cryptonote , "Run on stagenet. The wallet must be launched with --stagenet flag." , false }; + const command_line::arg_descriptor<bool> arg_regtest_on = { + "regtest" + , "Run in a regression testing mode." + , false + }; + const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty = { + "fixed-difficulty" + , "Fixed difficulty used for testing." + , 0 + }; const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir = { "data-dir" , "Specify data directory" @@ -251,6 +261,8 @@ namespace cryptonote command_line::add_arg(desc, arg_testnet_on); command_line::add_arg(desc, arg_stagenet_on); + command_line::add_arg(desc, arg_regtest_on); + command_line::add_arg(desc, arg_fixed_difficulty); command_line::add_arg(desc, arg_dns_checkpoints); command_line::add_arg(desc, arg_prep_blocks_threads); command_line::add_arg(desc, arg_fast_block_sync); @@ -373,7 +385,8 @@ namespace cryptonote { start_time = std::time(nullptr); - if (test_options != NULL) + const bool regtest = command_line::get_arg(vm, arg_regtest_on); + if (test_options != NULL || regtest) { m_nettype = FAKECHAIN; } @@ -430,6 +443,16 @@ namespace cryptonote blockchain_db_sync_mode sync_mode = db_defaultsync; uint64_t blocks_per_sync = 1; + if (m_nettype == FAKECHAIN) + { + // reset the db by removing the database file before opening it + if (!db->remove_data_file(filename)) + { + MERROR("Failed to remove data file in " << filename); + return false; + } + } + try { uint64_t db_flags = 0; @@ -507,7 +530,12 @@ namespace cryptonote m_blockchain_storage.set_user_options(blocks_threads, blocks_per_sync, sync_mode, fast_sync); - r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, test_options); + const std::pair<uint8_t, uint64_t> regtest_hard_forks[3] = {std::make_pair(1, 0), std::make_pair(Blockchain::get_hard_fork_heights(MAINNET).back().version, 1), std::make_pair(0, 0)}; + const cryptonote::test_options regtest_test_options = { + regtest_hard_forks + }; + const difficulty_type fixed_difficulty = command_line::get_arg(vm, arg_fixed_difficulty); + r = m_blockchain_storage.init(db.release(), m_nettype, m_offline, regtest ? ®test_test_options : test_options, fixed_difficulty); r = m_mempool.init(max_txpool_size); CHECK_AND_ASSERT_MES(r, false, "Failed to initialize memory pool"); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 03000383e..84e1bb918 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -60,6 +60,8 @@ namespace cryptonote extern const command_line::arg_descriptor<std::string, false, true, 2> arg_data_dir; extern const command_line::arg_descriptor<bool, false> arg_testnet_on; extern const command_line::arg_descriptor<bool, false> arg_stagenet_on; + extern const command_line::arg_descriptor<bool, false> arg_regtest_on; + extern const command_line::arg_descriptor<difficulty_type> arg_fixed_difficulty; extern const command_line::arg_descriptor<bool> arg_offline; /************************************************************************/ diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 8dee2b922..eac0f1f57 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -220,7 +220,7 @@ namespace cryptonote crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; cryptonote::txpool_tx_meta_t meta; - bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id, tvc, kept_by_block); + bool ch_inp_res = check_tx_inputs([&tx]()->cryptonote::transaction&{ return tx; }, id, max_used_block_height, max_used_block_id, tvc, kept_by_block); if(!ch_inp_res) { // if the transaction was valid before (kept_by_block), then it @@ -893,11 +893,15 @@ namespace cryptonote //--------------------------------------------------------------------------------- bool tx_memory_pool::on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id) { + CRITICAL_REGION_LOCAL(m_transactions_lock); + m_input_cache.clear(); return true; } //--------------------------------------------------------------------------------- bool tx_memory_pool::on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id) { + CRITICAL_REGION_LOCAL(m_transactions_lock); + m_input_cache.clear(); return true; } //--------------------------------------------------------------------------------- @@ -937,7 +941,26 @@ namespace cryptonote m_transactions_lock.unlock(); } //--------------------------------------------------------------------------------- - bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const + bool tx_memory_pool::check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block) const + { + if (!kept_by_block) + { + const std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>>::const_iterator i = m_input_cache.find(txid); + if (i != m_input_cache.end()) + { + max_used_block_height = std::get<2>(i->second); + max_used_block_id = std::get<3>(i->second); + tvc = std::get<1>(i->second); + return std::get<0>(i->second); + } + } + bool ret = m_blockchain.check_tx_inputs(get_tx(), max_used_block_height, max_used_block_id, tvc, kept_by_block); + if (!kept_by_block) + m_input_cache.insert(std::make_pair(txid, std::make_tuple(ret, tvc, max_used_block_height, max_used_block_id))); + return ret; + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const { struct transction_parser { @@ -966,7 +989,7 @@ namespace cryptonote return false;//we already sure that this tx is broken for this height tx_verification_context tvc; - if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc)) + if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc)) { txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); @@ -983,7 +1006,7 @@ namespace cryptonote return false; //check ring signature again, it is possible (with very small chance) that this transaction become again valid tx_verification_context tvc; - if(!m_blockchain.check_tx_inputs(lazy_tx(), txd.max_used_block_height, txd.max_used_block_id, tvc)) + if(!check_tx_inputs([&lazy_tx]()->cryptonote::transaction&{ return lazy_tx(); }, txid, txd.max_used_block_height, txd.max_used_block_id, tvc)) { txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); @@ -1176,7 +1199,7 @@ namespace cryptonote bool ready = false; try { - ready = is_transaction_ready_to_go(meta, txblob, tx); + ready = is_transaction_ready_to_go(meta, sorted_it->second, txblob, tx); } catch (const std::exception &e) { diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 5ccb71196..4ade7ddbe 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -499,12 +499,13 @@ namespace cryptonote * @brief check if a transaction is a valid candidate for inclusion in a block * * @param txd the transaction to check (and info about it) + * @param txid the txid of the transaction to check * @param txblob the transaction blob to check * @param tx the parsed transaction, if successful * * @return true if the transaction is good to go, otherwise false */ - bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const cryptonote::blobdata &txblob, transaction &tx) const; + bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, const crypto::hash &txid, const cryptonote::blobdata &txblob, transaction &tx) const; /** * @brief mark all transactions double spending the one passed @@ -557,6 +558,9 @@ private: */ sorted_tx_container::iterator find_tx_in_sorted_container(const crypto::hash& id) const; + //! cache/call Blockchain::check_tx_inputs results + bool check_tx_inputs(const std::function<cryptonote::transaction&(void)> &get_tx, const crypto::hash &txid, uint64_t &max_used_block_height, crypto::hash &max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false) const; + //! transactions which are unlikely to be included in blocks /*! These transactions are kept in RAM in case they *are* included * in a block eventually, but this container is not saved to disk. @@ -567,6 +571,8 @@ private: size_t m_txpool_max_size; size_t m_txpool_size; + + mutable std::unordered_map<crypto::hash, std::tuple<bool, tx_verification_context, uint64_t, crypto::hash>> m_input_cache; }; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 56aa1dc06..a931d3b57 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1168,8 +1168,20 @@ skip: + " blocks/sec), " + std::to_string(m_block_queue.get_data_size() / 1048576.f) + " MB queued"; if (ELPP->vRegistry()->allowed(el::Level::Debug, "sync-info")) timing_message += std::string(": ") + m_block_queue.get_overview(); - MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + if(m_core.get_target_blockchain_height() == 0){ + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() << timing_message); + } else { + const int completition_percent = (m_core.get_current_blockchain_height() * 100 / m_core.get_target_blockchain_height()); + if(completition_percent < 99) {//printing completion percent only if % is < of 99 cause for 99 >= this is useless + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + << " (" << completition_percent << "% " << (m_core.get_target_blockchain_height() - m_core.get_current_blockchain_height()) + << " blocks remaining)" << timing_message); + } else { + MGINFO_YELLOW(context << " Synced " << m_core.get_current_blockchain_height() << "/" << m_core.get_target_blockchain_height() + << timing_message); + } + } } } } @@ -1753,3 +1765,4 @@ skip: m_core.stop(); } } // namespace + diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index 3b1d0d826..84004c3c6 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -92,7 +92,6 @@ target_link_libraries(daemon daemonizer serialization daemon_rpc_server - epee ${EPEE_READLINE} version ${Boost_CHRONO_LIBRARY} diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index aa688294d..1638cf505 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -614,13 +614,13 @@ bool t_command_parser_executor::print_coinbase_tx_sum(const std::vector<std::str bool t_command_parser_executor::alt_chain_info(const std::vector<std::string>& args) { - if(args.size()) + if(args.size() > 1) { - std::cout << "No parameters allowed" << std::endl; + std::cout << "usage: alt_chain_info [block_hash]" << std::endl; return false; } - return m_executor.alt_chain_info(); + return m_executor.alt_chain_info(args.size() == 1 ? args[0] : ""); } bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector<std::string>& args) diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 144603597..35504f2c9 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -255,6 +255,7 @@ t_command_server::t_command_server( m_command_lookup.set_handler( "alt_chain_info" , std::bind(&t_command_parser_executor::alt_chain_info, &m_parser, p::_1) + , "alt_chain_info [blockhash]" , "Print the information about alternative chains." ); m_command_lookup.set_handler( diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 48671f190..ea24e32eb 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -77,9 +77,10 @@ public: const auto testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); const auto stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); + const auto regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on); const auto restricted = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_restricted_rpc); const auto main_rpc_port = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); - rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : cryptonote::MAINNET, main_rpc_port, "core"}); + rpcs.emplace_back(new t_rpc{vm, core, p2p, restricted, testnet ? cryptonote::TESTNET : stagenet ? cryptonote::STAGENET : regtest ? cryptonote::FAKECHAIN : cryptonote::MAINNET, main_rpc_port, "core"}); auto restricted_rpc_port_arg = cryptonote::core_rpc_server::arg_rpc_restricted_bind_port; if(!command_line::is_arg_defaulted(vm, restricted_rpc_port_arg)) diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 88bb1fd0c..82ece62a9 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -163,9 +163,10 @@ int main(int argc, char const * argv[]) const bool testnet = command_line::get_arg(vm, cryptonote::arg_testnet_on); const bool stagenet = command_line::get_arg(vm, cryptonote::arg_stagenet_on); - if (testnet && stagenet) + const bool regtest = command_line::get_arg(vm, cryptonote::arg_regtest_on); + if (testnet + stagenet + regtest > 1) { - std::cerr << "Can't specify more than one of --tesnet and --stagenet" << ENDL; + std::cerr << "Can't specify more than one of --tesnet and --stagenet and --regtest" << ENDL; return 1; } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 956c84a01..e2b42c806 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -75,7 +75,9 @@ namespace { << "hash: " << header.hash << std::endl << "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl << "POW hash: " << header.pow_hash << std::endl - << "reward: " << boost::lexical_cast<std::string>(header.reward); + << "block size: " << header.block_size << std::endl + << "num txes: " << header.num_txes << std::endl + << "reward: " << cryptonote::print_money(header.reward); } std::string get_human_time_ago(time_t t, time_t now) @@ -1628,7 +1630,7 @@ bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t cou return true; } -bool t_rpc_command_executor::alt_chain_info() +bool t_rpc_command_executor::alt_chain_info(const std::string &tip) { cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; @@ -1663,12 +1665,32 @@ bool t_rpc_command_executor::alt_chain_info() } } - tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:"; - for (const auto &chain: res.chains) + if (tip.empty()) { - uint64_t start_height = (chain.height - chain.length + 1); - tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1) - << " deep), diff " << chain.difficulty << ": " << chain.block_hash; + tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:"; + for (const auto &chain: res.chains) + { + uint64_t start_height = (chain.height - chain.length + 1); + tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1) + << " deep), diff " << chain.difficulty << ": " << chain.block_hash; + } + } + else + { + const auto i = std::find_if(res.chains.begin(), res.chains.end(), [&tip](cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info){ return info.block_hash == tip; }); + if (i != res.chains.end()) + { + const auto &chain = *i; + tools::success_msg_writer() << "Found alternate chain with tip " << tip; + uint64_t start_height = (chain.height - chain.length + 1); + tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1) + << " deep), diff " << chain.difficulty << ":"; + for (const std::string &block_id: chain.block_hashes) + tools::msg_writer() << " " << block_id; + tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block; + } + else + tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain"; } return true; } diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 46168c93b..9e6010c5b 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -143,7 +143,7 @@ public: bool print_coinbase_tx_sum(uint64_t height, uint64_t count); - bool alt_chain_info(); + bool alt_chain_info(const std::string &tip); bool print_blockchain_dynamic_stats(uint64_t nblocks); diff --git a/src/device/device.hpp b/src/device/device.hpp index 9df0cb39d..c21456daf 100644 --- a/src/device/device.hpp +++ b/src/device/device.hpp @@ -125,7 +125,7 @@ namespace hw { /* ======================================================================= */ virtual bool get_public_address(cryptonote::account_public_address &pubkey) = 0; virtual bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) = 0; - virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) = 0; + virtual bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) = 0; /* ======================================================================= */ /* SUB ADDRESS */ diff --git a/src/device/device_default.cpp b/src/device/device_default.cpp index 0071f7d4f..bf14813ea 100644 --- a/src/device/device_default.cpp +++ b/src/device/device_default.cpp @@ -100,14 +100,14 @@ namespace hw { /* WALLET & ADDRESS */ /* ======================================================================= */ - bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + bool device_default::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) { const crypto::secret_key &view_key = keys.m_view_secret_key; const crypto::secret_key &spend_key = keys.m_spend_secret_key; tools::scrubbed_arr<char, sizeof(view_key) + sizeof(spend_key) + 1> data; memcpy(data.data(), &view_key, sizeof(view_key)); memcpy(data.data() + sizeof(view_key), &spend_key, sizeof(spend_key)); data[sizeof(data) - 1] = CHACHA8_KEY_TAIL; - crypto::generate_chacha_key(data.data(), sizeof(data), key); + crypto::generate_chacha_key(data.data(), sizeof(data), key, kdf_rounds); return true; } bool device_default::get_public_address(cryptonote::account_public_address &pubkey) { diff --git a/src/device/device_default.hpp b/src/device/device_default.hpp index 771fbba72..8d841d9de 100644 --- a/src/device/device_default.hpp +++ b/src/device/device_default.hpp @@ -73,7 +73,7 @@ namespace hw { /* ======================================================================= */ bool get_public_address(cryptonote::account_public_address &pubkey) override; bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; - bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) override; /* ======================================================================= */ /* SUB ADDRESS */ diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index f716f8ded..7a34dad5e 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -274,22 +274,32 @@ namespace hw { /* ======================================================================= */ /* MISC */ /* ======================================================================= */ - bool device_ledger::reset() { - int offset; - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_RESET; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; + int device_ledger::set_command_header(BYTE ins, BYTE p1, BYTE p2) { + reset_buffer(); + int offset = 0; + this->buffer_send[0] = 0x00; + this->buffer_send[1] = ins; + this->buffer_send[2] = p1; + this->buffer_send[3] = p2; + this->buffer_send[4] = 0x00; + return 5; + } - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + int device_ledger::set_command_header_noopt(BYTE ins, BYTE p1, BYTE p2) { + int offset = set_command_header(ins, p1, p2); + //options + this->buffer_send[offset++] = 0; + this->buffer_send[4] = offset - 5; + return offset; + } + + void device_ledger::send_simple(BYTE ins, BYTE p1) { + this->length_send = set_command_header_noopt(ins, p1); + this->exchange(); + } + + bool device_ledger::reset() { + send_simple(INS_RESET); return true; } @@ -451,20 +461,10 @@ namespace hw { int offset; - reset_buffer(); - switch(mode) { case TRANSACTION_CREATE_REAL: case TRANSACTION_CREATE_FAKE: - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SET_SIGNATURE_MODE; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + offset = set_command_header_noopt(INS_SET_SIGNATURE_MODE, 1); //account this->buffer_send[offset] = mode; offset += 1; @@ -495,22 +495,7 @@ namespace hw { bool device_ledger::get_public_address(cryptonote::account_public_address &pubkey){ AUTO_LOCK_CMD(); - int offset; - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_KEY; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + send_simple(INS_GET_KEY, 1); memmove(pubkey.m_view_public_key.data, this->buffer_recv, 32); memmove(pubkey.m_spend_public_key.data, this->buffer_recv+32, 32); @@ -526,22 +511,7 @@ namespace hw { memset(skey.data, 0xFF, 32); //spcialkey, normal conf handled in decrypt - int offset; - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_KEY; - this->buffer_send[2] = 0x02; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + send_simple(INS_GET_KEY, 0x02); //View key is retrievied, if allowed, to speed up blockchain parsing memmove(this->viewkey.data, this->buffer_recv+0, 32); @@ -561,34 +531,20 @@ namespace hw { return true; } - bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) { + bool device_ledger::generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE crypto::chacha_key key_x; cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); - this->controle_device->generate_chacha_key(keys_x, key_x); + this->controle_device->generate_chacha_key(keys_x, key_x, kdf_rounds); #endif - reset_buffer(); - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_CHACHA8_PREKEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + send_simple(INS_GET_CHACHA8_PREKEY); char prekey[200]; memmove(prekey, &this->buffer_recv[0], 200); - crypto::generate_chacha_key_prehashed(&prekey[0], sizeof(prekey), key); + crypto::generate_chacha_key_prehashed(&prekey[0], sizeof(prekey), key, kdf_rounds); #ifdef DEBUG_HWDEVICE hw::ledger::check32("generate_chacha_key_prehashed", "key", (char*)key_x.data(), (char*)key.data()); @@ -627,19 +583,7 @@ namespace hw { crypto::derive_subaddress_public_key(pub, derivation, output_index,derived_pub); } else { - int offset =0; - - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_DERIVE_SUBADDRESS_PUBLIC_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_DERIVE_SUBADDRESS_PUBLIC_KEY); //pub memmove(this->buffer_send+offset, pub.data, 32); offset += 32; @@ -670,7 +614,6 @@ namespace hw { crypto::public_key device_ledger::get_subaddress_spend_public_key(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) { AUTO_LOCK_CMD(); crypto::public_key D; - int offset; #ifdef DEBUG_HWDEVICE const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); @@ -687,17 +630,7 @@ namespace hw { D = keys.m_account_address.m_spend_public_key; } else { - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY); //index static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length"); memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index)); @@ -732,7 +665,6 @@ namespace hw { cryptonote::account_public_address device_ledger::get_subaddress(const cryptonote::account_keys& keys, const cryptonote::subaddress_index &index) { AUTO_LOCK_CMD(); cryptonote::account_public_address address; - int offset; #ifdef DEBUG_HWDEVICE const cryptonote::account_keys keys_x = hw::ledger::decrypt(keys); @@ -751,17 +683,7 @@ namespace hw { if (index.is_zero()) { address = keys.m_account_address; } else { - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_SUBADDRESS; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + int offset = set_command_header_noopt(INS_GET_SUBADDRESS); //index static_assert(sizeof(cryptonote::subaddress_index) == 8, "cryptonote::subaddress_index shall be 8 bytes length"); memmove(this->buffer_send+offset, &index, sizeof(cryptonote::subaddress_index)); @@ -786,7 +708,6 @@ namespace hw { crypto::secret_key device_ledger::get_subaddress_secret_key(const crypto::secret_key &sec, const cryptonote::subaddress_index &index) { AUTO_LOCK_CMD(); crypto::secret_key sub_sec; - int offset; #ifdef DEBUG_HWDEVICE const crypto::secret_key sec_x = hw::ledger::decrypt(sec); @@ -798,17 +719,7 @@ namespace hw { hw::ledger::log_hexbuffer("get_subaddress_secret_key: [[OUT]] sub_sec", sub_sec_x.data, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GET_SUBADDRESS_SECRET_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_GET_SUBADDRESS_SECRET_KEY); //sec memmove(this->buffer_send+offset, sec.data, 32); offset += 32; @@ -839,16 +750,7 @@ namespace hw { AUTO_LOCK_CMD(); int offset, sw; - reset_buffer(); - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VERIFY_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + offset = set_command_header_noopt(INS_VERIFY_KEY); //sec memmove(this->buffer_send+offset, secret_key.data, 32); offset += 32; @@ -871,7 +773,6 @@ namespace hw { bool device_ledger::scalarmultKey(rct::key & aP, const rct::key &P, const rct::key &a) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const rct::key P_x = P; @@ -883,17 +784,7 @@ namespace hw { hw::ledger::log_hexbuffer("scalarmultKey: [[OUT]] aP", (char*)aP_x.bytes, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SECRET_SCAL_MUL_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_KEY); //pub memmove(this->buffer_send+offset, P.bytes, 32); offset += 32; @@ -918,7 +809,6 @@ namespace hw { bool device_ledger::scalarmultBase(rct::key &aG, const rct::key &a) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const rct::key a_x = hw::ledger::decrypt(a); @@ -928,17 +818,7 @@ namespace hw { hw::ledger::log_hexbuffer("scalarmultKey: [[OUT]] aG", (char*)aG_x.bytes, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SECRET_SCAL_MUL_BASE; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_SECRET_SCAL_MUL_BASE); //sec memmove(this->buffer_send+offset, a.bytes, 32); offset += 32; @@ -959,7 +839,6 @@ namespace hw { bool device_ledger::sc_secret_add( crypto::secret_key &r, const crypto::secret_key &a, const crypto::secret_key &b) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::secret_key a_x = hw::ledger::decrypt(a); @@ -968,17 +847,7 @@ namespace hw { this->controle_device->sc_secret_add(r_x, a_x, b_x); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SECRET_KEY_ADD; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_SECRET_KEY_ADD); //sec key memmove(this->buffer_send+offset, a.data, 32); offset += 32; @@ -1007,8 +876,6 @@ namespace hw { throw std::runtime_error("device generate key does not support recover"); } - int offset; - #ifdef DEBUG_HWDEVICE bool recover_x = recover; const crypto::secret_key recovery_key_x = recovery_key; @@ -1016,21 +883,7 @@ namespace hw { crypto::secret_key sec_x; #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GENERATE_KEYPAIR; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + send_simple(INS_GENERATE_KEYPAIR); //pub key memmove(pub.data, &this->buffer_recv[0], 32); @@ -1070,19 +923,7 @@ namespace hw { r = crypto::generate_key_derivation(pub, this->viewkey, derivation); } else { - int offset; - - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GEN_KEY_DERIVATION; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_GEN_KEY_DERIVATION); //pub memmove(this->buffer_send+offset, pub.data, 32); offset += 32; @@ -1131,7 +972,6 @@ namespace hw { bool device_ledger::derivation_to_scalar(const crypto::key_derivation &derivation, const size_t output_index, crypto::ec_scalar &res) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); @@ -1143,17 +983,7 @@ namespace hw { hw::ledger::log_hexbuffer("derivation_to_scalar: [[OUT]] res ", res_x.data, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_DERIVATION_TO_SCALAR; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_DERIVATION_TO_SCALAR); //derivattion memmove(this->buffer_send+offset, derivation.data, 32); offset += 32; @@ -1181,7 +1011,6 @@ namespace hw { bool device_ledger::derive_secret_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::secret_key &sec, crypto::secret_key &derived_sec) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); @@ -1195,17 +1024,7 @@ namespace hw { hw::ledger::log_hexbuffer("derive_secret_key: [[OUT]] derived_sec", derived_sec_x.data, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_DERIVE_SECRET_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_DERIVE_SECRET_KEY); //derivation memmove(this->buffer_send+offset, derivation.data, 32); offset += 32; @@ -1236,7 +1055,6 @@ namespace hw { bool device_ledger::derive_public_key(const crypto::key_derivation &derivation, const std::size_t output_index, const crypto::public_key &pub, crypto::public_key &derived_pub){ AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::key_derivation derivation_x = hw::ledger::decrypt(derivation); @@ -1250,17 +1068,7 @@ namespace hw { hw::ledger::log_hexbuffer("derive_public_key: [[OUT]] derived_pub ", derived_pub_x.data, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_DERIVE_PUBLIC_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_DERIVE_PUBLIC_KEY); //derivation memmove(this->buffer_send+offset, derivation.data, 32); offset += 32; @@ -1290,7 +1098,6 @@ namespace hw { bool device_ledger::secret_key_to_public_key(const crypto::secret_key &sec, crypto::public_key &pub) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::secret_key sec_x = hw::ledger::decrypt(sec); @@ -1303,17 +1110,7 @@ namespace hw { } #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_SECRET_KEY_TO_PUBLIC_KEY; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_SECRET_KEY_TO_PUBLIC_KEY); //sec key memmove(this->buffer_send+offset, sec.data, 32); offset += 32; @@ -1334,7 +1131,6 @@ namespace hw { bool device_ledger::generate_key_image(const crypto::public_key &pub, const crypto::secret_key &sec, crypto::key_image &image){ AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::public_key pub_x = pub; @@ -1346,17 +1142,7 @@ namespace hw { hw::ledger::log_hexbuffer("generate_key_image: [[OUT]] image ", image_x.data, 32); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_GEN_KEY_IMAGE; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0; - offset += 1; + int offset = set_command_header_noopt(INS_GEN_KEY_IMAGE); //pub memmove(this->buffer_send+offset, pub.data, 32); offset += 32; @@ -1384,20 +1170,10 @@ namespace hw { bool device_ledger::open_tx(crypto::secret_key &tx_key) { AUTO_LOCK_CMD(); - int offset; - reset_buffer(); key_map.clear(); + int offset = set_command_header_noopt(INS_OPEN_TX, 0x01); - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_OPEN_TX; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; //account this->buffer_send[offset+0] = 0x00; this->buffer_send[offset+1] = 0x00; @@ -1416,7 +1192,6 @@ namespace hw { bool device_ledger::encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const crypto::public_key public_key_x = public_key; @@ -1425,17 +1200,7 @@ namespace hw { this->controle_device->encrypt_payment_id(payment_id_x, public_key_x, secret_key_x); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_STEALTH; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + int offset = set_command_header_noopt(INS_STEALTH); //pub memmove(&this->buffer_send[offset], public_key.data, 32); offset += 32; @@ -1467,7 +1232,6 @@ namespace hw { bool device_ledger::ecdhEncode(rct::ecdhTuple & unmasked, const rct::key & AKout) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const rct::key AKout_x = hw::ledger::decrypt(AKout); @@ -1475,17 +1239,7 @@ namespace hw { this->controle_device->ecdhEncode(unmasked_x, AKout_x); #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_BLIND; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + int offset = set_command_header_noopt(INS_BLIND); // AKout memmove(this->buffer_send+offset, AKout.bytes, 32); offset += 32; @@ -1515,7 +1269,6 @@ namespace hw { bool device_ledger::ecdhDecode(rct::ecdhTuple & masked, const rct::key & AKout) { AUTO_LOCK_CMD(); - int offset; #ifdef DEBUG_HWDEVICE const rct::key AKout_x = hw::ledger::decrypt(AKout); @@ -1523,17 +1276,8 @@ namespace hw { this->controle_device->ecdhDecode(masked_x, AKout_x); #endif - reset_buffer(); + int offset = set_command_header_noopt(INS_UNBLIND); - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_UNBLIND; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; // AKout memmove(this->buffer_send+offset, AKout.bytes, 32); offset += 32; @@ -1583,16 +1327,7 @@ namespace hw { data = blob.data(); // ====== u8 type, varint txnfee ====== - int offset; - - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VALIDATE; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x01; - this->buffer_send[4] = 0x00; - offset = 5; + int offset = set_command_header(INS_VALIDATE, 0x01, 0x01); //options this->buffer_send[offset] = (inputs_size == 0)?0x00:0x80; offset += 1; @@ -1620,13 +1355,7 @@ namespace hw { //pseudoOuts if ((type == rct::RCTTypeSimple) || (type == rct::RCTTypeSimpleBulletproof)) { for ( i = 0; i < inputs_size; i++) { - reset_buffer(); - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VALIDATE; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = i+2; - this->buffer_send[4] = 0x00; - offset = 5; + offset = set_command_header(INS_VALIDATE, 0x01, i+2); //options this->buffer_send[offset] = (i==inputs_size-1)? 0x00:0x80; offset += 1; @@ -1653,14 +1382,7 @@ namespace hw { log_hexbuffer("Pout not found", (char*)outPk[i].dest.bytes, 32); CHECK_AND_ASSERT_THROW_MES(found, "Pout not found"); } - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VALIDATE; - this->buffer_send[2] = 0x02; - this->buffer_send[3] = i+1; - this->buffer_send[4] = 0x00; - offset = 5; + offset = set_command_header(INS_VALIDATE, 0x02, i+1); //options this->buffer_send[offset] = (i==outputs_size-1)? 0x00:0x80 ; offset += 1; @@ -1705,14 +1427,7 @@ namespace hw { // ====== C[], message, proof====== C_offset = kv_offset; for (i = 0; i < outputs_size; i++) { - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VALIDATE; - this->buffer_send[2] = 0x03; - this->buffer_send[3] = i+1; - this->buffer_send[4] = 0x00; - offset = 5; + offset = set_command_header(INS_VALIDATE, 0x03, i+1); //options this->buffer_send[offset] = 0x80 ; offset += 1; @@ -1727,17 +1442,7 @@ namespace hw { } - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_VALIDATE; - this->buffer_send[2] = 0x03; - this->buffer_send[3] = i+1; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + offset = set_command_header_noopt(INS_VALIDATE, 0x03, i+1); //message memmove(this->buffer_send+offset, hashes[0].bytes,32); offset += 32; @@ -1762,7 +1467,6 @@ namespace hw { bool device_ledger::mlsag_prepare(const rct::key &H, const rct::key &xx, rct::key &a, rct::key &aG, rct::key &aHP, rct::key &II) { AUTO_LOCK_CMD(); - int offset; unsigned char options; #ifdef DEBUG_HWDEVICE @@ -1774,17 +1478,7 @@ namespace hw { rct::key II_x; #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_MLSAG; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; + int offset = set_command_header_noopt(INS_MLSAG, 0x01); //value H memmove(this->buffer_send+offset, H.bytes, 32); offset += 32; @@ -1817,7 +1511,6 @@ namespace hw { bool device_ledger::mlsag_prepare(rct::key &a, rct::key &aG) { AUTO_LOCK_CMD(); - int offset; unsigned char options; #ifdef DEBUG_HWDEVICE @@ -1825,21 +1518,7 @@ namespace hw { rct::key aG_x; #endif - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_MLSAG; - this->buffer_send[2] = 0x01; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); + send_simple(INS_MLSAG, 0x01); memmove(a.bytes, &this->buffer_recv[32*0], 32); memmove(aG.bytes, &this->buffer_recv[32*1], 32); @@ -1855,7 +1534,6 @@ namespace hw { bool device_ledger::mlsag_hash(const rct::keyV &long_message, rct::key &c) { AUTO_LOCK_CMD(); - int offset; unsigned char options; size_t cnt; @@ -1867,14 +1545,7 @@ namespace hw { cnt = long_message.size(); for (size_t i = 0; i<cnt; i++) { - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_MLSAG; - this->buffer_send[2] = 0x02; - this->buffer_send[3] = i+1; - this->buffer_send[4] = 0x00; - offset = 5; + int offset = set_command_header(INS_MLSAG, 0x02, i+1); //options this->buffer_send[offset] = (i==(cnt-1))?0x00:0x80; //last @@ -1899,7 +1570,6 @@ namespace hw { bool device_ledger::mlsag_sign(const rct::key &c, const rct::keyV &xx, const rct::keyV &alpha, const size_t rows, const size_t dsRows, rct::keyV &ss) { AUTO_LOCK_CMD(); - int offset; CHECK_AND_ASSERT_THROW_MES(dsRows<=rows, "dsRows greater than rows"); CHECK_AND_ASSERT_THROW_MES(xx.size() == rows, "xx size does not match rows"); @@ -1917,14 +1587,7 @@ namespace hw { #endif for (size_t j = 0; j < dsRows; j++) { - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_MLSAG; - this->buffer_send[2] = 0x03; - this->buffer_send[3] = j+1; - this->buffer_send[4] = 0x00; - offset = 5; + int offset = set_command_header(INS_MLSAG, 0x03, j+1); //options this->buffer_send[offset] = 0x00; if (j==(dsRows-1)) { @@ -1961,24 +1624,7 @@ namespace hw { bool device_ledger::close_tx() { AUTO_LOCK_CMD(); - int offset; - - reset_buffer(); - - this->buffer_send[0] = 0x00; - this->buffer_send[1] = INS_CLOSE_TX; - this->buffer_send[2] = 0x00; - this->buffer_send[3] = 0x00; - this->buffer_send[4] = 0x00; - offset = 5; - //options - this->buffer_send[offset] = 0x00; - offset += 1; - - this->buffer_send[4] = offset-5; - this->length_send = offset; - this->exchange(); - + send_simple(INS_CLOSE_TX); return true; } diff --git a/src/device/device_ledger.hpp b/src/device/device_ledger.hpp index b62bdf959..e6c6e5b52 100644 --- a/src/device/device_ledger.hpp +++ b/src/device/device_ledger.hpp @@ -102,6 +102,9 @@ namespace hw { void logRESP(void); unsigned int exchange(unsigned int ok=0x9000, unsigned int mask=0xFFFF); void reset_buffer(void); + int set_command_header(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00); + int set_command_header_noopt(BYTE ins, BYTE p1 = 0x00, BYTE p2 = 0x00); + void send_simple(BYTE ins, BYTE p1 = 0x00); // hw running mode device_mode mode; @@ -153,7 +156,7 @@ namespace hw { /* ======================================================================= */ bool get_public_address(cryptonote::account_public_address &pubkey) override; bool get_secret_keys(crypto::secret_key &viewkey , crypto::secret_key &spendkey) override; - bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key) override; + bool generate_chacha_key(const cryptonote::account_keys &keys, crypto::chacha_key &key, uint64_t kdf_rounds) override; /* ======================================================================= */ diff --git a/src/mnemonics/esperanto.h b/src/mnemonics/esperanto.h index cb377a58e..a1d1a3f30 100644 --- a/src/mnemonics/esperanto.h +++ b/src/mnemonics/esperanto.h @@ -37,7 +37,7 @@ * Sources:
* Baza Radikaro Oficiala
* Reta Vortaro (http://www.reta-vortaro.de/revo/)
- * Esperanto Panorama - Esperanto-English Dictionary (http://www.esperanto-panorama.net/vortaro/eoen.htm)
+ * Esperanto Panorama - Esperanto-English Dictionary (https://www.esperanto-panorama.net/vortaro/eoen.htm)
* ESPDIC - Paul Denisowski (http://www.denisowski.org/Esperanto/ESPDIC/espdic.txt)
*/
diff --git a/src/mnemonics/lojban.h b/src/mnemonics/lojban.h index 412531a23..0966a1169 100644 --- a/src/mnemonics/lojban.h +++ b/src/mnemonics/lojban.h @@ -35,7 +35,7 @@ /*
* Word list authored by: sorpaas
* Sources:
- * lo gimste jo'u lo ma'oste (http://guskant.github.io/lojbo/gismu-cmavo.html)
+ * lo gimste jo'u lo ma'oste (https://guskant.github.io/lojbo/gismu-cmavo.html)
* N-grams of Lojban corpus (https://mw.lojban.org/papri/N-grams_of_Lojban_corpus)
*/
diff --git a/src/p2p/CMakeLists.txt b/src/p2p/CMakeLists.txt index 83bdffab5..9b924907e 100644 --- a/src/p2p/CMakeLists.txt +++ b/src/p2p/CMakeLists.txt @@ -38,7 +38,6 @@ source_group(p2p FILES ${P2P}) monero_add_library(p2p ${P2P}) target_link_libraries(p2p PUBLIC - epee version cryptonote_core ${UPNP_LIBRARIES} diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 85470f799..74924e4f4 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -402,6 +402,9 @@ namespace nodetool full_addrs.insert("162.210.173.150:38080"); full_addrs.insert("162.210.173.151:38080"); } + else if (nettype == cryptonote::FAKECHAIN) + { + } else { full_addrs.insert("107.152.130.98:18080"); @@ -934,7 +937,7 @@ namespace nodetool bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()), epee::string_tools::num_to_string_fast(ipv4.port()), m_config.m_net_config.connection_timeout, - con); + con, m_bind_ip.empty() ? "0.0.0.0" : m_bind_ip); if(!res) { @@ -999,7 +1002,7 @@ namespace nodetool bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(ipv4.ip()), epee::string_tools::num_to_string_fast(ipv4.port()), m_config.m_net_config.connection_timeout, - con); + con, m_bind_ip.empty() ? "0.0.0.0" : m_bind_ip); if (!res) { bool is_priority = is_priority_node(na); @@ -1614,7 +1617,7 @@ namespace nodetool return false; } return true; - }); + }, m_bind_ip.empty() ? "0.0.0.0" : m_bind_ip); if(!r) { LOG_WARNING_CC(context, "Failed to call connect_async, network error."); diff --git a/src/ringct/rctOps.cpp b/src/ringct/rctOps.cpp index 68cc43128..50693bad7 100644 --- a/src/ringct/rctOps.cpp +++ b/src/ringct/rctOps.cpp @@ -62,14 +62,13 @@ namespace rct { //generates a random scalar which can be used as a secret key or mask void skGen(key &sk) { - sk = crypto::rand<key>(); - sc_reduce32(sk.bytes); + random32_unbiased(sk.bytes); } //generates a random scalar which can be used as a secret key or mask key skGen() { - key sk = crypto::rand<key>(); - sc_reduce32(sk.bytes); + key sk; + skGen(sk); return sk; } @@ -79,9 +78,8 @@ namespace rct { CHECK_AND_ASSERT_THROW_MES(rows > 0, "0 keys requested"); keyV rv(rows); size_t i = 0; - crypto::rand(rows * sizeof(key), (uint8_t*)&rv[0]); for (i = 0 ; i < rows ; i++) { - sc_reduce32(rv[i].bytes); + skGen(rv[i]); } return rv; } diff --git a/src/ringct/rctSigs.cpp b/src/ringct/rctSigs.cpp index cc6fbe738..f74216ed4 100644 --- a/src/ringct/rctSigs.cpp +++ b/src/ringct/rctSigs.cpp @@ -147,7 +147,7 @@ namespace rct { //This is a just slghtly more efficient version than the ones described below //(will be explained in more detail in Ring Multisig paper //These are aka MG signatutes in earlier drafts of the ring ct paper - // c.f. http://eprint.iacr.org/2015/1098 section 2. + // c.f. https://eprint.iacr.org/2015/1098 section 2. // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly @@ -244,7 +244,7 @@ namespace rct { //This is a just slghtly more efficient version than the ones described below //(will be explained in more detail in Ring Multisig paper //These are aka MG signatutes in earlier drafts of the ring ct paper - // c.f. http://eprint.iacr.org/2015/1098 section 2. + // c.f. https://eprint.iacr.org/2015/1098 section 2. // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly @@ -307,7 +307,7 @@ namespace rct { //proveRange and verRange //proveRange gives C, and mask such that \sumCi = C - // c.f. http://eprint.iacr.org/2015/1098 section 5.1 + // c.f. https://eprint.iacr.org/2015/1098 section 5.1 // and Ci is a commitment to either 0 or 2^i, i=0,...,63 // thus this proves that "amount" is in [0, 2^64] // mask is a such that C = aG + bH, and b = amount @@ -339,7 +339,7 @@ namespace rct { //proveRange and verRange //proveRange gives C, and mask such that \sumCi = C - // c.f. http://eprint.iacr.org/2015/1098 section 5.1 + // c.f. https://eprint.iacr.org/2015/1098 section 5.1 // and Ci is a commitment to either 0 or 2^i, i=0,...,63 // thus this proves that "amount" is in [0, 2^64] // mask is a such that C = aG + bH, and b = amount @@ -441,7 +441,7 @@ namespace rct { //Ring-ct MG sigs //Prove: - // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. + // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10. // This does the MG sig on the "dest" part of the given key matrix, and // the last row is the sum of input commitments from that column - sum output commitments // this shows that sum inputs = sum outputs @@ -527,7 +527,7 @@ namespace rct { //Ring-ct MG sigs //Prove: - // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. + // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10. // This does the MG sig on the "dest" part of the given key matrix, and // the last row is the sum of input commitments from that column - sum output commitments // this shows that sum inputs = sum outputs @@ -650,7 +650,7 @@ namespace rct { // Also contains masked "amount" and "mask" so the receiver can see how much they received //verRct: // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct - //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) + //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number // Note: For txn fees, the last index in the amounts vector should contain that @@ -828,7 +828,7 @@ namespace rct { // Also contains masked "amount" and "mask" so the receiver can see how much they received //verRct: // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct - //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) + //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number bool verRct(const rctSig & rv, bool semantics) { @@ -1023,7 +1023,7 @@ namespace rct { // Also contains masked "amount" and "mask" so the receiver can see how much they received //verRct: // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct - //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) + //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number xmr_amount decodeRct(const rctSig & rv, const key & sk, unsigned int i, key & mask, hw::device &hwdev) { diff --git a/src/ringct/rctSigs.h b/src/ringct/rctSigs.h index b8aab0f11..5a9b2dd44 100644 --- a/src/ringct/rctSigs.h +++ b/src/ringct/rctSigs.h @@ -70,7 +70,7 @@ namespace rct { //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. + // c.f. https://eprint.iacr.org/2015/1098 section 2. // Gen creates a signature which proves that for some column in the keymatrix "pk" // the signer knows a secret key for each row in that column // Ver verifies that the MG sig was created correctly @@ -80,7 +80,7 @@ namespace rct { //proveRange and verRange //proveRange gives C, and mask such that \sumCi = C - // c.f. http://eprint.iacr.org/2015/1098 section 5.1 + // c.f. https://eprint.iacr.org/2015/1098 section 5.1 // and Ci is a commitment to either 0 or 2^i, i=0,...,63 // thus this proves that "amount" is in [0, 2^64] // mask is a such that C = aG + bH, and b = amount @@ -90,7 +90,7 @@ namespace rct { //Ring-ct MG sigs //Prove: - // c.f. http://eprint.iacr.org/2015/1098 section 4. definition 10. + // c.f. https://eprint.iacr.org/2015/1098 section 4. definition 10. // This does the MG sig on the "dest" part of the given key matrix, and // the last row is the sum of input commitments from that column - sum output commitments // this shows that sum inputs = sum outputs @@ -116,7 +116,7 @@ namespace rct { // Also contains masked "amount" and "mask" so the receiver can see how much they received //verRct: // verifies that all signatures (rangeProogs, MG sig, sum inputs = outputs) are correct - //decodeRct: (c.f. http://eprint.iacr.org/2015/1098 section 5.1.1) + //decodeRct: (c.f. https://eprint.iacr.org/2015/1098 section 5.1.1) // uses the attached ecdh info to find the amounts represented by each output commitment // must know the destination private key to find the correct amount, else will return a random number rctSig genRct(const key &message, const ctkeyV & inSk, const keyV & destinations, const std::vector<xmr_amount> & amounts, const ctkeyM &mixRing, const keyV &amount_keys, const multisig_kLRki *kLRki, multisig_out *msout, unsigned int index, ctkeyV &outSk, bool bulletproof, hw::device &hwdev); diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index eba1e3d93..844291d0c 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -150,7 +150,7 @@ namespace rct { }; //just contains the necessary keys to represent MLSAG sigs - //c.f. http://eprint.iacr.org/2015/1098 + //c.f. https://eprint.iacr.org/2015/1098 struct mgSig { keyM ss; key cc; diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 7162317ed..4f8f96524 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -111,7 +111,6 @@ target_link_libraries(rpc common cryptonote_core cryptonote_protocol - epee ${Boost_REGEX_LIBRARY} ${Boost_THREAD_LIBRARY} PRIVATE diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index b55b1994b..0a6daf8f0 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -47,7 +47,6 @@ using namespace epee; #include "rpc/rpc_args.h" #include "core_rpc_server_error_codes.h" #include "p2p/net_node.h" -#include "get_output_distribution_cache.h" #include "version.h" #undef MONERO_DEFAULT_LOG_CATEGORY @@ -194,6 +193,7 @@ namespace cryptonote res.mainnet = m_nettype == MAINNET; res.testnet = m_nettype == TESTNET; res.stagenet = m_nettype == STAGENET; + res.nettype = m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : m_nettype == STAGENET ? "stagenet" : "fakechain"; res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1); res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median(); @@ -207,6 +207,7 @@ namespace cryptonote boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); res.was_bootstrap_ever_used = m_was_bootstrap_ever_used; } + res.database_size = m_core.get_blockchain_storage().get_db().get_database_size(); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -982,11 +983,11 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin) + bool core_rpc_server::on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, bool request_has_rpc_origin) { PERF_TIMER(on_get_transaction_pool_hashes); bool r; - if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r)) + if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN>(invoke_http_mode::JON, "/get_transaction_pool_hashes.bin", req, res, r)) return r; m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted); @@ -994,6 +995,22 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin) + { + PERF_TIMER(on_get_transaction_pool_hashes); + bool r; + if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_TRANSACTION_POOL_HASHES>(invoke_http_mode::JON, "/get_transaction_pool_hashes", req, res, r)) + return r; + + std::vector<crypto::hash> tx_hashes; + m_core.get_pool_transaction_hashes(tx_hashes, !request_has_rpc_origin || !m_restricted); + res.tx_hashes.reserve(tx_hashes.size()); + for (const crypto::hash &tx_hash: tx_hashes) + res.tx_hashes.push_back(epee::string_tools::pod_to_hex(tx_hash)); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin) { PERF_TIMER(on_get_transaction_pool_stats); @@ -1210,6 +1227,68 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp) + { + PERF_TIMER(on_generateblocks); + + CHECK_CORE_READY(); + + res.status = CORE_RPC_STATUS_OK; + + if(m_core.get_nettype() != FAKECHAIN) + { + error_resp.code = CORE_RPC_ERROR_CODE_REGTEST_REQUIRED; + error_resp.message = "Regtest required when generating blocks"; + return false; + } + + COMMAND_RPC_GETBLOCKTEMPLATE::request template_req; + COMMAND_RPC_GETBLOCKTEMPLATE::response template_res; + COMMAND_RPC_SUBMITBLOCK::request submit_req; + COMMAND_RPC_SUBMITBLOCK::response submit_res; + + template_req.reserve_size = 1; + template_req.wallet_address = req.wallet_address; + submit_req.push_back(boost::value_initialized<std::string>()); + res.height = m_core.get_blockchain_storage().get_current_blockchain_height(); + + bool r; + + for(size_t i = 0; i < req.amount_of_blocks; i++) + { + r = on_getblocktemplate(template_req, template_res, error_resp); + res.status = template_res.status; + + if (!r) return false; + + blobdata blockblob; + if(!string_tools::parse_hexstr_to_binbuff(template_res.blocktemplate_blob, blockblob)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB; + error_resp.message = "Wrong block blob"; + return false; + } + block b = AUTO_VAL_INIT(b); + if(!parse_and_validate_block_from_blob(blockblob, b)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB; + error_resp.message = "Wrong block blob"; + return false; + } + miner::find_nonce_for_given_block(b, template_res.difficulty, template_res.height); + + submit_req.front() = string_tools::buff_to_hex_nodelimer(block_to_blob(b)); + r = on_submitblock(submit_req, submit_res, error_resp); + res.status = submit_res.status; + + if (!r) return false; + + res.height = template_res.height; + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ uint64_t core_rpc_server::get_block_reward(const block& blk) { uint64_t reward = 0; @@ -1565,6 +1644,7 @@ namespace cryptonote res.mainnet = m_nettype == MAINNET; res.testnet = m_nettype == TESTNET; res.stagenet = m_nettype == STAGENET; + res.nettype = m_nettype == MAINNET ? "mainnet" : m_nettype == TESTNET ? "testnet" : m_nettype == STAGENET ? "stagenet" : "fakechain"; res.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.height - 1); res.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit(); res.block_size_median = m_core.get_blockchain_storage().get_current_cumulative_blocksize_median(); @@ -1578,6 +1658,7 @@ namespace cryptonote boost::shared_lock<boost::shared_mutex> lock(m_bootstrap_daemon_mutex); res.was_bootstrap_ever_used = m_was_bootstrap_ever_used; } + res.database_size = m_core.get_blockchain_storage().get_db().get_database_size(); return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -1775,10 +1856,22 @@ namespace cryptonote PERF_TIMER(on_get_alternate_chains); try { - std::list<std::pair<Blockchain::block_extended_info, uint64_t>> chains = m_core.get_blockchain_storage().get_alternative_chains(); + std::list<std::pair<Blockchain::block_extended_info, std::vector<crypto::hash>>> chains = m_core.get_blockchain_storage().get_alternative_chains(); for (const auto &i: chains) { - res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second, i.first.cumulative_difficulty}); + res.chains.push_back(COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info{epee::string_tools::pod_to_hex(get_block_hash(i.first.bl)), i.first.height, i.second.size(), i.first.cumulative_difficulty, {}, std::string()}); + res.chains.back().block_hashes.reserve(i.second.size()); + for (const crypto::hash &block_id: i.second) + res.chains.back().block_hashes.push_back(epee::string_tools::pod_to_hex(block_id)); + if (i.first.height < i.second.size()) + { + res.status = "Error finding alternate chain attachment point"; + return true; + } + cryptonote::block main_chain_parent_block; + try { main_chain_parent_block = m_core.get_blockchain_storage().get_db().get_block_from_height(i.first.height - i.second.size()); } + catch (const std::exception &e) { res.status = "Error finding alternate chain attachment point"; return true; } + res.chains.back().main_chain_parent_block = epee::string_tools::pod_to_hex(get_block_hash(main_chain_parent_block)); } res.status = CORE_RPC_STATUS_OK; } @@ -2071,6 +2164,10 @@ namespace cryptonote bool core_rpc_server::on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp) { PERF_TIMER(on_get_output_distribution); + bool r; + if (use_bootstrap_daemon_if_necessary<COMMAND_RPC_GET_OUTPUT_DISTRIBUTION>(invoke_http_mode::JON_RPC, "get_output_distribution", req, res, r)) + return r; + try { for (uint64_t amount: req.amounts) @@ -2087,38 +2184,17 @@ namespace cryptonote if (d.cached && amount == 0 && d.cached_from == req.from_height && d.cached_to == req.to_height) { - res.distributions.push_back({amount, d.cached_start_height, d.cached_distribution, d.cached_base}); - if (req.cumulative) + res.distributions.push_back({amount, d.cached_start_height, req.binary, d.cached_distribution, d.cached_base}); + if (!req.cumulative) { auto &distribution = res.distributions.back().distribution; - distribution[0] += d.cached_base; - for (size_t n = 1; n < distribution.size(); ++n) - distribution[n] += distribution[n-1]; + for (size_t n = distribution.size() - 1; n > 0; --n) + distribution[n] -= distribution[n-1]; + distribution[0] -= d.cached_base; } continue; } - // this is a slow operation, so we have precomputed caches of common cases - bool found = false; - for (const auto &slot: get_output_distribution_cache) - { - if (slot.amount == amount && slot.from_height == req.from_height && slot.to_height == req.to_height) - { - res.distributions.push_back({amount, slot.start_height, slot.distribution, slot.base}); - found = true; - if (req.cumulative) - { - auto &distribution = res.distributions.back().distribution; - distribution[0] += slot.base; - for (size_t n = 1; n < distribution.size(); ++n) - distribution[n] += distribution[n-1]; - } - break; - } - } - if (found) - continue; - std::vector<uint64_t> distribution; uint64_t start_height, base; if (!m_core.get_output_distribution(amount, req.from_height, req.to_height, start_height, distribution, base)) @@ -2144,14 +2220,14 @@ namespace cryptonote d.cached = true; } - if (req.cumulative) + if (!req.cumulative) { - distribution[0] += base; - for (size_t n = 1; n < distribution.size(); ++n) - distribution[n] += distribution[n-1]; + for (size_t n = distribution.size() - 1; n > 0; --n) + distribution[n] -= distribution[n-1]; + distribution[0] -= base; } - res.distributions.push_back({amount, start_height, std::move(distribution), base}); + res.distributions.push_back({amount, start_height, req.binary, std::move(distribution), base}); } } catch (const std::exception &e) diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 324f219f8..166020d01 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -107,7 +107,8 @@ namespace cryptonote MAP_URI_AUTO_JON2_IF("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL, !m_restricted) MAP_URI_AUTO_JON2_IF("/set_log_categories", on_set_log_categories, COMMAND_RPC_SET_LOG_CATEGORIES, !m_restricted) MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL) - MAP_URI_AUTO_JON2("/get_transaction_pool_hashes.bin", on_get_transaction_pool_hashes, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES) + MAP_URI_AUTO_JON2("/get_transaction_pool_hashes.bin", on_get_transaction_pool_hashes_bin, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN) + MAP_URI_AUTO_JON2("/get_transaction_pool_hashes", on_get_transaction_pool_hashes, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES) MAP_URI_AUTO_JON2("/get_transaction_pool_stats", on_get_transaction_pool_stats, COMMAND_RPC_GET_TRANSACTION_POOL_STATS) MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted) MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO) @@ -129,6 +130,7 @@ namespace cryptonote MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE) MAP_JON_RPC_WE("submit_block", on_submitblock, COMMAND_RPC_SUBMITBLOCK) MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK) + MAP_JON_RPC_WE_IF("generateblocks", on_generateblocks, COMMAND_RPC_GENERATEBLOCKS, !m_restricted) MAP_JON_RPC_WE("get_last_block_header", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER) MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER) MAP_JON_RPC_WE("get_block_header_by_hash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH) @@ -180,6 +182,7 @@ namespace cryptonote bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res); bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res); bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin = true); + bool on_get_transaction_pool_hashes_bin(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response& res, bool request_has_rpc_origin = true); bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin = true); bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin = true); bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res); @@ -196,6 +199,7 @@ namespace cryptonote bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp); bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp); bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp); + bool on_generateblocks(const COMMAND_RPC_GENERATEBLOCKS::request& req, COMMAND_RPC_GENERATEBLOCKS::response& res, epee::json_rpc::error& error_resp); bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp); bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp); bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 49b730149..e2d120cad 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -49,7 +49,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 1 -#define CORE_RPC_VERSION_MINOR 20 +#define CORE_RPC_VERSION_MINOR 21 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -955,6 +955,7 @@ namespace cryptonote bool mainnet; bool testnet; bool stagenet; + std::string nettype; std::string top_block_hash; uint64_t cumulative_difficulty; uint64_t block_size_limit; @@ -966,6 +967,7 @@ namespace cryptonote std::string bootstrap_daemon_address; uint64_t height_without_bootstrap; bool was_bootstrap_ever_used; + uint64_t database_size; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) @@ -984,6 +986,7 @@ namespace cryptonote KV_SERIALIZE(mainnet) KV_SERIALIZE(testnet) KV_SERIALIZE(stagenet) + KV_SERIALIZE(nettype) KV_SERIALIZE(top_block_hash) KV_SERIALIZE(cumulative_difficulty) KV_SERIALIZE(block_size_limit) @@ -995,6 +998,7 @@ namespace cryptonote KV_SERIALIZE(bootstrap_daemon_address) KV_SERIALIZE(height_without_bootstrap) KV_SERIALIZE(was_bootstrap_ever_used) + KV_SERIALIZE(database_size) END_KV_SERIALIZE_MAP() }; }; @@ -1151,6 +1155,31 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GENERATEBLOCKS + { + struct request + { + uint64_t amount_of_blocks; + std::string wallet_address; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount_of_blocks) + KV_SERIALIZE(wallet_address) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t height; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; struct block_header_response { @@ -1489,7 +1518,7 @@ namespace cryptonote }; }; - struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES + struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN { struct request { @@ -1511,6 +1540,28 @@ namespace cryptonote }; }; + struct COMMAND_RPC_GET_TRANSACTION_POOL_HASHES + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector<std::string> tx_hashes; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(tx_hashes) + KV_SERIALIZE(untrusted) + END_KV_SERIALIZE_MAP() + }; + }; + struct tx_backlog_entry { uint64_t blob_size; @@ -2090,12 +2141,16 @@ namespace cryptonote uint64_t height; uint64_t length; uint64_t difficulty; + std::vector<std::string> block_hashes; + std::string main_chain_parent_block; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(block_hash) KV_SERIALIZE(height) KV_SERIALIZE(length) KV_SERIALIZE(difficulty) + KV_SERIALIZE(block_hashes) + KV_SERIALIZE(main_chain_parent_block) END_KV_SERIALIZE_MAP() }; @@ -2231,12 +2286,14 @@ namespace cryptonote uint64_t from_height; uint64_t to_height; bool cumulative; + bool binary; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amounts) KV_SERIALIZE_OPT(from_height, (uint64_t)0) KV_SERIALIZE_OPT(to_height, (uint64_t)0) KV_SERIALIZE_OPT(cumulative, false) + KV_SERIALIZE_OPT(binary, true) END_KV_SERIALIZE_MAP() }; @@ -2244,13 +2301,18 @@ namespace cryptonote { uint64_t amount; uint64_t start_height; + bool binary; std::vector<uint64_t> distribution; uint64_t base; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) KV_SERIALIZE(start_height) - KV_SERIALIZE_CONTAINER_POD_AS_BLOB(distribution) + KV_SERIALIZE(binary) + if (this_ref.binary) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(distribution) + else + KV_SERIALIZE(distribution) KV_SERIALIZE(base) END_KV_SERIALIZE_MAP() }; @@ -2259,10 +2321,12 @@ namespace cryptonote { std::string status; std::vector<distribution> distributions; + bool untrusted; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(status) KV_SERIALIZE(distributions) + KV_SERIALIZE(untrusted) END_KV_SERIALIZE_MAP() }; }; diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h index 69caaa6a6..5a754749f 100644 --- a/src/rpc/core_rpc_server_error_codes.h +++ b/src/rpc/core_rpc_server_error_codes.h @@ -42,5 +42,6 @@ #define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE -10 #define CORE_RPC_ERROR_CODE_UNSUPPORTED_RPC -11 #define CORE_RPC_ERROR_CODE_MINING_TO_SUBADDRESS -12 +#define CORE_RPC_ERROR_CODE_REGTEST_REQUIRED -13 diff --git a/src/rpc/get_output_distribution_cache.h b/src/rpc/get_output_distribution_cache.h deleted file mode 100644 index 6495e7d4c..000000000 --- a/src/rpc/get_output_distribution_cache.h +++ /dev/null @@ -1,113 +0,0 @@ -static const struct -{ - uint64_t amount; - uint64_t from_height; - uint64_t to_height; - uint64_t start_height; - uint64_t base; - std::vector<uint64_t> distribution; -} -get_output_distribution_cache[] = -{ - { - 0, - 1544704, - 1546001, - 1544704, - 5143500, - { - 5, 38, 37, 33, 39, 7, 1, 1, 5, 9, 7, 5, 17, 5, 3, 9, 3, 17, 5, 17, 1, 1, 15, 13, 3, 10, 5, 3, 34, 1, 45, 7, - 5, 17, 5, 22, 3, 1, 17, 16, 5, 1, 3, 43, 5, 13, 3, 23, 9, 7, 9, 13, 1, 11, 1, 17, 1, 3, 16, 11, 5, 11, 7, 7, - 33, 11, 7, 1, 5, 1, 21, 19, 1, 17, 1, 49, 17, 3, 3, 9, 35, 46, 46, 39, 26, 33, 21, 3, 23, 3, 9, 37, 1, 33, 11, 32, - 1, 13, 16, 12, 3, 21, 1, 18, 3, 19, 1, 25, 5, 3, 18, 7, 17, 5, 9, 15, 7, 7, 11, 9, 9, 17, 5, 16, 1, 3, 13, 3, - 5, 5, 5, 13, 5, 9, 5, 13, 3, 17, 15, 36, 13, 3, 20, 12, 6, 23, 17, 10, 22, 23, 1, 7, 21, 6, 23, 1, 3, 19, 13, 1, - 3, 43, 35, 13, 1, 31, 7, 3, 17, 1, 15, 5, 11, 15, 24, 1, 18, 13, 5, 15, 1, 29, 3, 3, 13, 3, 15, 7, 17, 3, 1, 1, - 17, 1, 1, 45, 39, 27, 45, 46, 34, 7, 3, 3, 9, 3, 3, 11, 7, 5, 9, 25, 19, 3, 33, 1, 5, 17, 1, 45, 4, 1, 45, 11, - 44, 32, 3, 1, 3, 7, 17, 15, 5, 45, 35, 41, 1, 35, 3, 3, 19, 1, 9, 17, 29, 29, 3, 1, 13, 1, 3, 47, 21, 13, 7, 1, - 7, 5, 1, 11, 1, 40, 9, 7, 3, 3, 13, 25, 1, 47, 5, 7, 3, 7, 31, 40, 34, 6, 3, 15, 3, 31, 5, 13, 27, 9, 12, 21, - 3, 1, 19, 1, 19, 5, 47, 49, 47, 42, 50, 34, 29, 23, 1, 5, 9, 16, 11, 7, 1, 19, 7, 5, 1, 15, 1, 1, 9, 13, 9, 5, - 27, 3, 3, 29, 1, 33, 3, 9, 5, 35, 5, 1, 17, 7, 3, 39, 3, 28, 19, 1, 1, 9, 1, 3, 27, 1, 37, 3, 1, 1, 16, 3, - 25, 11, 5, 3, 33, 45, 17, 11, 7, 22, 9, 1, 5, 5, 5, 15, 1, 15, 9, 7, 11, 13, 37, 49, 46, 38, 11, 1, 25, 1, 13, 18, - 3, 7, 39, 3, 37, 19, 35, 3, 1, 3, 19, 1, 3, 15, 21, 3, 27, 1, 45, 48, 1, 13, 29, 9, 1, 1, 46, 43, 5, 15, 3, 7, - 29, 26, 5, 5, 21, 37, 17, 21, 3, 13, 1, 5, 1, 17, 5, 31, 13, 1, 11, 3, 46, 9, 3, 7, 1, 1, 41, 1, 21, 1, 5, 12, - 7, 13, 9, 25, 1, 47, 47, 48, 48, 48, 48, 48, 47, 48, 45, 45, 33, 52, 50, 46, 45, 47, 35, 41, 38, 35, 42, 38, 34, 41, 39, 35, - 51, 51, 45, 43, 49, 52, 53, 45, 42, 46, 37, 53, 49, 41, 46, 49, 46, 47, 48, 37, 41, 33, 43, 38, 15, 3, 3, 27, 11, 5, 23, 13, - 1, 1, 37, 3, 15, 3, 30, 13, 3, 45, 12, 3, 5, 11, 1, 1, 21, 9, 11, 19, 1, 1, 1, 25, 5, 21, 3, 1, 32, 44, 3, 33, - 11, 7, 5, 23, 1, 37, 47, 48, 48, 48, 48, 48, 48, 46, 47, 47, 50, 45, 49, 50, 46, 47, 49, 45, 51, 49, 50, 49, 49, 46, 47, 48, - 46, 48, 46, 50, 46, 43, 46, 46, 48, 47, 46, 47, 45, 49, 46, 43, 50, 45, 45, 49, 45, 48, 45, 49, 48, 45, 45, 51, 45, 51, 45, 46, - 52, 45, 45, 51, 51, 52, 44, 45, 52, 50, 50, 46, 47, 51, 51, 46, 47, 47, 47, 50, 47, 51, 48, 49, 51, 50, 48, 48, 48, 50, 49, 49, - 52, 52, 49, 50, 49, 49, 49, 51, 52, 49, 52, 50, 49, 47, 29, 15, 39, 17, 31, 5, 40, 5, 18, 23, 25, 7, 35, 26, 5, 31, 49, 22, - 3, 17, 7, 49, 7, 49, 47, 12, 44, 46, 36, 15, 3, 1, 47, 13, 35, 40, 5, 21, 19, 39, 21, 33, 31, 29, 1, 1, 37, 1, 15, 47, - 7, 7, 47, 41, 13, 3, 47, 31, 9, 33, 13, 43, 29, 5, 1, 9, 33, 7, 27, 15, 15, 25, 5, 43, 22, 31, 7, 1, 47, 1, 15, 27, - 3, 27, 45, 15, 1, 36, 17, 1, 23, 39, 38, 45, 7, 7, 19, 7, 11, 47, 33, 16, 3, 45, 45, 45, 9, 27, 3, 3, 21, 3, 7, 21, - 7, 3, 43, 1, 17, 1, 45, 37, 46, 5, 5, 13, 46, 40, 48, 48, 45, 34, 1, 46, 19, 25, 9, 7, 47, 23, 37, 31, 3, 25, 13, 46, - 31, 25, 5, 46, 35, 52, 11, 23, 27, 4, 15, 11, 11, 11, 9, 34, 7, 9, 15, 34, 9, 27, 37, 28, 25, 45, 13, 30, 5, 25, 15, 7, - 3, 19, 27, 1, 7, 11, 1, 32, 3, 45, 11, 9, 21, 25, 9, 13, 13, 1, 7, 1, 33, 11, 5, 3, 3, 27, 27, 5, 3, 37, 17, 17, - 3, 7, 5, 13, 1, 3, 44, 45, 26, 25, 1, 13, 3, 13, 3, 11, 1, 11, 7, 45, 3, 3, 1, 43, 1, 19, 3, 1, 15, 5, 39, 7, - 7, 1, 9, 1, 11, 19, 3, 35, 29, 7, 15, 11, 40, 7, 44, 38, 34, 7, 9, 7, 1, 27, 1, 9, 5, 45, 1, 21, 3, 1, 5, 9, - 3, 21, 23, 33, 3, 1, 7, 3, 3, 7, 41, 9, 7, 1, 5, 31, 9, 7, 1, 1, 11, 41, 51, 20, 9, 47, 39, 17, 9, 35, 1, 41, - 1, 19, 1, 19, 15, 1, 13, 5, 23, 15, 9, 15, 17, 1, 15, 27, 33, 31, 29, 7, 13, 1, 5, 45, 5, 1, 1, 11, 1, 13, 3, 7, - 9, 1, 13, 39, 3, 33, 5, 3, 7, 7, 5, 29, 11, 1, 7, 1, 15, 3, 13, 3, 15, 3, 3, 1, 5, 1, 9, 1, 44, 49, 24, 25, - 1, 1, 34, 22, 7, 5, 5, 5, 10, 9, 13, 3, 9, 1, 9, 19, 7, 43, 48, 7, 11, 7, 3, 3, 7, 21, 1, 1, 3, 3, 11, 31, - 1, 1, 13, 22, 23, 7, 27, 9, 3, 3, 21, 1, 35, 21, 9, 11, 13, 39, 1, 3, 7, 23, 3, 28, 3, 45, 47, 38, 32, 37, 34, 1, - 23, 3, 3, 1, 19, 19, 1, 5, 13, 1, 5, 11, 38, 3, 1, 36, 13, 1, 1, 23, 5, 17, 11, 1, 13, 1, 3, 7, 11, 3, 33, 7, - 19, 5, 5, 1, 1, 3, 5, 41, 1, 3, 25, 1, 7, 7, 9, 3, 11, 3, 13, 5, 7, 1, 3, 9, 1, 1, 43, 47, 47, 47, 17, 7, - 17, 3, 19, 1, 9, 9, 33, 22, 1, 25, 1, 3, 3, 32, 5, 1, 23, 9, 5, 1, 31, 5, 9, 1, 3, 7, 19, 1, 12, 11, 5, 1, - 1, 9, 25, 15, 15, 13, 5, 3, 15, 1, 17, 1, 1, 5, 5, 41, 11, 15, 7, 3, 21, 21, 35, 22, 46, 35, 3, 27, 5, 3, 45, 22, - 27, 1, 19, 9, 1, 25, 1, 29, 3, 5, 25, 17, 27, 5, 19, 5, 25, 7, 19, 1, 9, 21, 3, 7, 29, 27, 17, 3, 3, 15, 7, 19, - 5, 25, 1, 23, 45, 4, 31, 1, 37, 14, 29, 3, 29, 1, 23, 29, 19, 11, 1, 13, 13, 9, 1, 25, 1, 33, 1, 37, 37, 23, 7, 21, - 7, 3, 13, 7, 3, 7, 21, 11, 9, 1, 31, 3, 1, 7, 39, 46, 3, 30, - }, - }, - { - 0, - 1562704, - 1564001, - 1562704, - 5521986, - { - 35, 45, 23, 3, 44, 47, 44, 3, 17, 35, 7, 11, 7, 29, 43, 27, 11, 7, 5, 31, 13, 9, 45, 45, 7, 42, 17, 15, 19, 11, 45, 19, - 45, 46, 45, 46, 32, 34, 43, 34, 46, 47, 45, 30, 17, 45, 46, 36, 35, 38, 19, 9, 23, 17, 3, 19, 31, 41, 35, 24, 15, 45, 15, 5, - 11, 5, 19, 11, 11, 7, 15, 19, 45, 34, 7, 7, 29, 1, 9, 36, 7, 44, 45, 33, 25, 8, 17, 7, 44, 43, 48, 45, 42, 46, 40, 44, - 1, 43, 45, 46, 46, 35, 19, 19, 23, 5, 13, 19, 7, 16, 9, 3, 25, 34, 3, 27, 9, 39, 3, 43, 21, 1, 45, 45, 39, 25, 23, 13, - 39, 39, 3, 45, 43, 46, 44, 40, 39, 33, 45, 47, 38, 45, 45, 39, 47, 47, 45, 46, 35, 45, 43, 47, 45, 40, 34, 42, 42, 48, 49, 47, - 47, 48, 47, 45, 43, 48, 37, 48, 41, 45, 48, 34, 42, 44, 9, 19, 27, 1, 47, 47, 43, 25, 29, 5, 5, 21, 39, 35, 43, 37, 13, 45, - 25, 31, 26, 47, 45, 23, 23, 39, 32, 25, 44, 47, 35, 47, 15, 17, 7, 9, 5, 35, 31, 3, 45, 47, 46, 13, 17, 48, 45, 9, 13, 45, - 45, 31, 1, 53, 44, 46, 39, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 47, 47, 47, 47, 47, 47, 47, 47, 53, 49, 45, 45, 50, - 50, 27, 43, 46, 47, 46, 45, 48, 36, 42, 42, 46, 45, 47, 41, 45, 43, 47, 38, 48, 47, 33, 11, 45, 46, 34, 42, 32, 3, 45, 37, 45, - 15, 3, 45, 29, 31, 9, 5, 3, 27, 5, 21, 25, 7, 15, 46, 34, 5, 3, 17, 3, 9, 13, 7, 11, 3, 1, 34, 13, 7, 45, 33, 26, - 9, 5, 9, 41, 43, 34, 3, 35, 3, 17, 37, 11, 17, 3, 15, 27, 15, 45, 46, 13, 26, 16, 11, 7, 5, 45, 38, 45, 45, 22, 44, 44, - 43, 6, 11, 35, 15, 44, 17, 27, 13, 3, 40, 5, 9, 7, 35, 19, 5, 5, 1, 28, 33, 15, 45, 5, 29, 3, 31, 12, 5, 32, 24, 3, - 23, 13, 47, 45, 42, 46, 39, 21, 21, 1, 44, 44, 47, 41, 5, 1, 11, 36, 20, 5, 45, 39, 45, 45, 44, 45, 32, 22, 40, 11, 38, 1, - 45, 46, 37, 9, 23, 9, 15, 44, 7, 16, 38, 46, 11, 14, 24, 19, 19, 7, 26, 25, 45, 37, 17, 1, 35, 1, 3, 28, 3, 11, 22, 13, - 3, 1, 7, 38, 5, 3, 1, 26, 1, 3, 43, 44, 46, 45, 21, 11, 1, 44, 27, 1, 11, 26, 10, 44, 45, 45, 45, 47, 47, 45, 48, 45, - 38, 9, 5, 44, 46, 27, 3, 12, 1, 11, 3, 44, 43, 1, 5, 2, 46, 17, 13, 19, 1, 12, 7, 23, 1, 17, 6, 13, 3, 5, 27, 7, - 46, 36, 19, 25, 1, 1, 3, 8, 15, 3, 45, 45, 45, 37, 6, 15, 3, 5, 38, 14, 41, 1, 13, 45, 45, 39, 44, 29, 43, 48, 51, 50, - 37, 5, 17, 46, 47, 31, 5, 42, 49, 38, 39, 24, 7, 11, 44, 35, 21, 6, 15, 5, 47, 13, 28, 45, 34, 27, 24, 15, 35, 13, 7, 25, - 43, 13, 14, 5, 3, 5, 46, 45, 45, 35, 5, 21, 28, 3, 13, 4, 30, 19, 45, 45, 40, 37, 5, 40, 17, 9, 3, 9, 13, 4, 17, 33, - 44, 39, 17, 45, 28, 5, 11, 45, 19, 45, 21, 44, 31, 43, 49, 48, 15, 3, 1, 44, 45, 43, 11, 1, 1, 27, 43, 45, 39, 3, 1, 3, - 5, 31, 1, 43, 23, 19, 7, 5, 45, 31, 11, 7, 3, 9, 5, 7, 13, 43, 47, 45, 46, 47, 14, 3, 25, 45, 7, 17, 32, 21, 3, 17, - 5, 11, 31, 40, 45, 20, 45, 45, 32, 38, 47, 38, 45, 41, 49, 30, 45, 5, 36, 31, 22, 3, 46, 45, 13, 21, 23, 5, 46, 45, 33, 19, - 25, 1, 7, 13, 5, 44, 23, 29, 23, 24, 7, 5, 37, 13, 29, 13, 7, 17, 7, 43, 3, 21, 7, 44, 1, 19, 15, 9, 34, 43, 26, 3, - 17, 5, 6, 5, 7, 3, 33, 35, 43, 41, 48, 47, 30, 45, 19, 7, 5, 33, 11, 34, 25, 1, 21, 11, 29, 7, 1, 4, 5, 10, 14, 3, - 44, 11, 47, 45, 33, 3, 9, 7, 40, 23, 9, 1, 3, 1, 7, 5, 9, 9, 6, 11, 45, 41, 45, 19, 5, 11, 10, 39, 9, 19, 3, 11, - 43, 42, 1, 13, 35, 5, 32, 7, 5, 5, 43, 37, 3, 32, 17, 3, 23, 1, 13, 45, 17, 1, 21, 45, 43, 46, 49, 47, 45, 30, 9, 31, - 19, 42, 19, 44, 17, 14, 19, 25, 1, 7, 5, 45, 19, 13, 7, 3, 1, 1, 9, 21, 37, 9, 11, 1, 3, 37, 27, 13, 5, 21, 33, 3, - 27, 9, 27, 1, 39, 1, 46, 21, 10, 13, 21, 40, 22, 35, 41, 9, 33, 3, 17, 8, 45, 46, 42, 46, 47, 47, 47, 48, 48, 47, 43, 48, - 37, 39, 50, 35, 3, 40, 45, 40, 46, 36, 34, 28, 9, 9, 37, 9, 5, 7, 13, 31, 1, 7, 3, 3, 44, 45, 25, 15, 1, 21, 43, 25, - 1, 38, 34, 42, 31, 23, 33, 35, 37, 20, 7, 15, 3, 7, 7, 27, 45, 45, 48, 47, 45, 44, 47, 23, 25, 36, 11, 3, 18, 24, 27, 13, - 41, 13, 5, 5, 7, 19, 15, 7, 5, 14, 45, 45, 37, 1, 5, 17, 21, 41, 17, 37, 53, 41, 45, 45, 45, 45, 45, 45, 45, 45, 43, 47, - 47, 48, 53, 47, 47, 47, 49, 27, 45, 47, 47, 47, 47, 45, 45, 45, 47, 43, 48, 34, 34, 43, 46, 15, 37, 21, 5, 27, 11, 1, 9, 7, - 19, 15, 1, 1, 19, 3, 36, 27, 29, 13, 21, 9, 17, 5, 16, 45, 23, 34, 3, 1, 7, 25, 28, 13, 29, 15, 11, 19, 17, 1, 27, 23, - 31, 19, 41, 41, 40, 47, 28, 31, 26, 26, 36, 17, 5, 1, 23, 1, 45, 34, 49, 51, 34, 43, 37, 5, 41, 15, 5, 21, 1, 7, 9, 19, - 5, 11, 39, 19, 45, 45, 38, 17, 9, 1, 15, 11, 5, 13, 47, 46, 48, 45, 19, 32, 7, 19, 5, 7, 23, 29, 5, 45, 41, 37, 1, 5, - 27, 5, 5, 7, 19, 9, 1, 35, 48, 38, 38, 39, 42, 43, 21, 23, 43, 41, 7, 3, 7, 13, 1, 46, 47, 46, 23, 46, 45, 25, 7, 9, - 21, 7, 41, 13, 20, 1, 21, 15, 37, 5, 40, 45, 45, 5, 45, 46, 15, 33, 46, 12, 13, 7, 24, 7, 5, 30, 7, 46, 13, 8, 44, 35, - 45, 33, 40, 36, 47, 47, 29, 43, 36, 43, 45, 42, 36, 19, 7, 7, 43, 3, 44, 25, 48, 29, 11, 45, 30, 1, 17, 13, 25, 1, 48, 45, - 45, 45, 44, 49, 37, 9, 21, 17, 15, 7, 15, 25, 1, 1, 9, 43, 33, 11, 3, 29, 45, 45, 9, 7, 7, 27, 47, 45, 47, 48, 45, 47, - 26, 1, 43, 15, 45, 17, 1, 5, 35, 31, 9, 3, 9, 19, 9, 21, 43, 5, 27, 1, 5, 9, 4, 34, 19, 3, 7, 11, 45, 46, 45, 45, - 46, 47, 47, 44, 45, 43, 27, 9, 17, 15, 19, 44, 45, 46, 47, 47, 45, 45, - } - } -}; - diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index 17ae9629f..fc1b2329d 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -181,6 +181,7 @@ namespace rpc bool mainnet; bool testnet; bool stagenet; + std::string nettype; crypto::hash top_block_hash; uint64_t cumulative_difficulty; uint64_t block_size_limit; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index a7fb58ee4..c2467b863 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -1175,6 +1175,7 @@ void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& in INSERT_INTO_JSON_OBJECT(val, doc, white_peerlist_size, info.white_peerlist_size); INSERT_INTO_JSON_OBJECT(val, doc, grey_peerlist_size, info.grey_peerlist_size); INSERT_INTO_JSON_OBJECT(val, doc, testnet, info.testnet); + INSERT_INTO_JSON_OBJECT(val, doc, nettype, info.nettype); INSERT_INTO_JSON_OBJECT(val, doc, top_block_hash, info.top_block_hash); INSERT_INTO_JSON_OBJECT(val, doc, cumulative_difficulty, info.cumulative_difficulty); INSERT_INTO_JSON_OBJECT(val, doc, block_size_limit, info.block_size_limit); @@ -1200,6 +1201,7 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& inf GET_FROM_JSON_OBJECT(val, info.white_peerlist_size, white_peerlist_size); GET_FROM_JSON_OBJECT(val, info.grey_peerlist_size, grey_peerlist_size); GET_FROM_JSON_OBJECT(val, info.testnet, testnet); + GET_FROM_JSON_OBJECT(val, info.nettype, nettype); GET_FROM_JSON_OBJECT(val, info.top_block_hash, top_block_hash); GET_FROM_JSON_OBJECT(val, info.cumulative_difficulty, cumulative_difficulty); GET_FROM_JSON_OBJECT(val, info.block_size_limit, block_size_limit); diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index 8bb295931..c31cdebde 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -48,7 +48,6 @@ target_link_libraries(simplewallet cncrypto common mnemonics - epee ${EPEE_READLINE} version ${Boost_CHRONO_LIBRARY} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 08f0a20f4..69f7aebab 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -1423,7 +1423,6 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args) } ring.push_back(offset); ptr += read; - MGINFO("read offset: " << offset); } if (!valid) continue; @@ -1826,6 +1825,7 @@ bool simple_wallet::set_auto_refresh(const std::vector<std::string> &args/* = st if (pwd_container) { parse_bool_and_use(args[1], [&](bool auto_refresh) { + m_auto_refresh_enabled.store(false, std::memory_order_relaxed); m_wallet->auto_refresh(auto_refresh); m_idle_mutex.lock(); m_auto_refresh_enabled.store(auto_refresh, std::memory_order_relaxed); @@ -2092,6 +2092,19 @@ bool simple_wallet::set_segregation_height(const std::vector<std::string> &args/ return true; } +bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string> &args/* = std::vector<std::string>()*/) +{ + const auto pwd_container = get_and_verify_password(); + if (pwd_container) + { + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->ignore_fractional_outputs(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); + } + return true; +} + bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { if(args.empty()) @@ -2157,6 +2170,10 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::locked_transfer, this, _1), tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]"), tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)")); + m_cmd_binder.set_handler("locked_sweep_all", + boost::bind(&simple_wallet::locked_sweep_all, this, _1), + tr("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]"), + tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index<N1>[,<N2>,...]\" is specified, the wallet sweeps outputs received by those address indices. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability.")); m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::sweep_unmixable, this, _1), tr("Send all unmixable outputs to yourself with ring_size 1")); @@ -2479,6 +2496,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) const std::pair<size_t, size_t> lookahead = m_wallet->get_subaddress_lookahead(); success_msg_writer() << "subaddress-lookahead = " << lookahead.first << ":" << lookahead.second; success_msg_writer() << "segregation-height = " << m_wallet->segregation_height(); + success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs(); return true; } else @@ -2533,6 +2551,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args) CHECK_SIMPLE_VARIABLE("key-reuse-mitigation2", set_key_reuse_mitigation2, tr("0 or 1")); CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>")); CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer")); + CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1")); } fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; @@ -3955,6 +3974,24 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, tr("txid ") << txid << ", " << print_money(amount) << ", " << tr("idx ") << subaddr_index; + + const uint64_t warn_height = m_wallet->nettype() == TESTNET ? 1000000 : m_wallet->nettype() == STAGENET ? 50000 : 1650000; + if (height >= warn_height) + { + std::vector<tx_extra_field> tx_extra_fields; + parse_tx_extra(tx.extra, tx_extra_fields); // failure ok + tx_extra_nonce extra_nonce; + if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + { + crypto::hash8 payment_id8 = crypto::null_hash8; + if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) + message_writer() << + tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead"); + else + message_writer(console_color_red, false) << + tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead"); + } + } if (m_auto_refresh_refreshing) m_cmd_binder.print_prompt(); else @@ -4278,12 +4315,7 @@ uint64_t simple_wallet::get_daemon_blockchain_height(std::string& err) { throw std::runtime_error("simple_wallet null wallet"); } - - COMMAND_RPC_GET_HEIGHT::request req; - COMMAND_RPC_GET_HEIGHT::response res = boost::value_initialized<COMMAND_RPC_GET_HEIGHT::response>(); - bool r = m_wallet->invoke_http_json("/getheight", req, res); - err = interpret_rpc_response(r, res.status); - return res.height; + return m_wallet->get_daemon_blockchain_height(err); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args) @@ -4553,6 +4585,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri return true; } payment_id_seen = true; + message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead"); } uint64_t locked_blocks = 0; @@ -4861,6 +4894,11 @@ bool simple_wallet::locked_transfer(const std::vector<std::string> &args_) return transfer_main(TransferLocked, args_); } //---------------------------------------------------------------------------------------------------- +bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_) +{ + return sweep_main(0, true, args_); +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) { @@ -4968,12 +5006,16 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &args_) +bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args_) { - // sweep_all [index=<N1>[,<N2>,...]] [<ring_size>] <address> [<payment_id>] + auto print_usage = [below]() + { + fail_msg_writer() << boost::format(tr("usage: %s [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]")) % (below ? "sweep_below" : "sweep_all"); + }; if (args_.size() == 0) { fail_msg_writer() << tr("No address given"); + print_usage(); return true; } @@ -4987,7 +5029,10 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a if (local_args.size() > 0 && local_args[0].substr(0, 6) == "index=") { if (!parse_subaddress_indices(local_args[0], subaddr_indices)) + { + print_usage(); return true; + } local_args.erase(local_args.begin()); } @@ -5024,9 +5069,44 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a return true; } + uint64_t unlock_block = 0; + if (locked) { + uint64_t locked_blocks = 0; + + if (local_args.size() < 2) { + fail_msg_writer() << tr("missing lockedblocks parameter"); + return true; + } + + try + { + locked_blocks = boost::lexical_cast<uint64_t>(local_args[1]); + } + catch (const std::exception &e) + { + fail_msg_writer() << tr("bad locked_blocks parameter"); + return true; + } + if (locked_blocks > 1000000) + { + fail_msg_writer() << tr("Locked blocks too high, max 1000000 (˜4 yrs)"); + return true; + } + std::string err; + uint64_t bc_height = get_daemon_blockchain_height(err); + if (!err.empty()) + { + fail_msg_writer() << tr("failed to get blockchain height: ") << err; + return true; + } + unlock_block = bc_height + locked_blocks; + + local_args.erase(local_args.begin() + 1); + } + std::vector<uint8_t> extra; bool payment_id_seen = false; - if (2 >= local_args.size()) + if (local_args.size() >= 2) { std::string payment_id_str = local_args.back(); @@ -5055,6 +5135,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a if(!r && local_args.size() == 3) { fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str; + print_usage(); return true; } if (payment_id_seen) @@ -5065,6 +5146,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[0], oa_prompter)) { fail_msg_writer() << tr("failed to parse address"); + print_usage(); return true; } @@ -5106,7 +5188,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted()); + auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted()); if (ptx_vector.empty()) { @@ -5402,7 +5484,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::sweep_all(const std::vector<std::string> &args_) { - return sweep_main(0, args_); + return sweep_main(0, false, args_); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::sweep_below(const std::vector<std::string> &args_) @@ -5418,7 +5500,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_) fail_msg_writer() << tr("invalid amount threshold"); return true; } - return sweep_main(below, std::vector<std::string>(++args_.begin(), args_.end())); + return sweep_main(below, false, std::vector<std::string>(++args_.begin(), args_.end())); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::donate(const std::vector<std::string> &args_) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 7a788d432..b8f7bb84b 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -137,6 +137,7 @@ namespace cryptonote bool set_key_reuse_mitigation2(const std::vector<std::string> &args = std::vector<std::string>()); bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>()); bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>()); + bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>()); bool help(const std::vector<std::string> &args = std::vector<std::string>()); bool start_mining(const std::vector<std::string> &args); bool stop_mining(const std::vector<std::string> &args); @@ -152,7 +153,8 @@ namespace cryptonote bool transfer(const std::vector<std::string> &args); bool transfer_new(const std::vector<std::string> &args); bool locked_transfer(const std::vector<std::string> &args); - bool sweep_main(uint64_t below, const std::vector<std::string> &args); + bool locked_sweep_all(const std::vector<std::string> &args); + bool sweep_main(uint64_t below, bool locked, const std::vector<std::string> &args); bool sweep_all(const std::vector<std::string> &args); bool sweep_below(const std::vector<std::string> &args); bool sweep_single(const std::vector<std::string> &args); diff --git a/src/version.cpp.in b/src/version.cpp.in index a03da7889..55ba51f50 100644 --- a/src/version.cpp.in +++ b/src/version.cpp.in @@ -1,5 +1,5 @@ #define DEF_MONERO_VERSION_TAG "@VERSIONTAG@" -#define DEF_MONERO_VERSION "0.12.2.0-master" +#define DEF_MONERO_VERSION "0.12.3.0-master" #define DEF_MONERO_RELEASE_NAME "Lithium Luna" #define DEF_MONERO_VERSION_FULL DEF_MONERO_VERSION "-" DEF_MONERO_VERSION_TAG diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index a5a4c7f56..a16f4fe19 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -85,7 +85,6 @@ monero_add_executable(wallet_rpc_server target_link_libraries(wallet_rpc_server PRIVATE wallet - epee rpc_base cryptonote_core cncrypto diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 3f6bfec9e..f7c074b5a 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -366,7 +366,7 @@ void Wallet::error(const std::string &category, const std::string &str) { } ///////////////////////// WalletImpl implementation //////////////////////// -WalletImpl::WalletImpl(NetworkType nettype) +WalletImpl::WalletImpl(NetworkType nettype, bool restricted, uint64_t kdf_rounds) :m_wallet(nullptr) , m_status(Wallet::Status_Ok) , m_trustedDaemon(false) @@ -377,7 +377,7 @@ WalletImpl::WalletImpl(NetworkType nettype) , m_rebuildWalletCache(false) , m_is_connected(false) { - m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype)); + m_wallet = new tools::wallet2(static_cast<cryptonote::network_type>(nettype), restricted, kdf_rounds); m_history = new TransactionHistoryImpl(this); m_wallet2Callback = new Wallet2CallbackImpl(this); m_wallet->callback(m_wallet2Callback); @@ -2205,6 +2205,20 @@ void WalletImpl::keyReuseMitigation2(bool mitigation) m_wallet->key_reuse_mitigation2(mitigation); } +bool WalletImpl::lockKeysFile() +{ + return m_wallet->lock_keys_file(); +} + +bool WalletImpl::unlockKeysFile() +{ + return m_wallet->unlock_keys_file(); +} + +bool WalletImpl::isKeysFileLocked() +{ + return m_wallet->is_keys_file_locked(); +} } // namespace namespace Bitmonero = Monero; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index eefb2fe94..28b73423d 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -52,7 +52,7 @@ struct Wallet2CallbackImpl; class WalletImpl : public Wallet { public: - WalletImpl(NetworkType nettype = MAINNET); + WalletImpl(NetworkType nettype = MAINNET, bool restricted = false, uint64_t kdf_rounds = 1); ~WalletImpl(); bool create(const std::string &path, const std::string &password, const std::string &language); @@ -188,6 +188,9 @@ public: virtual void segregatePreForkOutputs(bool segregate) override; virtual void segregationHeight(uint64_t height) override; virtual void keyReuseMitigation2(bool mitigation) override; + virtual bool lockKeysFile() override; + virtual bool unlockKeysFile() override; + virtual bool isKeysFileLocked() override; private: void clearStatus() const; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index f54255e91..5a52c6b17 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -900,6 +900,12 @@ struct Wallet //! Initiates a light wallet import wallet request virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) = 0; + + //! locks/unlocks the keys file; returns true on success + virtual bool lockKeysFile() = 0; + virtual bool unlockKeysFile() = 0; + //! returns true if the keys file is locked + virtual bool isKeysFileLocked() = 0; }; /** @@ -914,9 +920,10 @@ struct WalletManager * \param password Password of wallet file * \param language Language to be used to generate electrum seed mnemonic * \param nettype Network type + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if created successfully) */ - virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype) = 0; + virtual Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; Wallet * createWallet(const std::string &path, const std::string &password, const std::string &language, bool testnet = false) // deprecated { return createWallet(path, password, language, testnet ? TESTNET : MAINNET); @@ -927,9 +934,10 @@ struct WalletManager * \param path Name of wallet file * \param password Password of wallet file * \param nettype Network type + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if opened successfully) */ - virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype) = 0; + virtual Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) = 0; Wallet * openWallet(const std::string &path, const std::string &password, bool testnet = false) // deprecated { return openWallet(path, password, testnet ? TESTNET : MAINNET); @@ -942,10 +950,11 @@ struct WalletManager * \param mnemonic mnemonic (25 words electrum seed) * \param nettype Network type * \param restoreHeight restore from start height + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, - NetworkType nettype = MAINNET, uint64_t restoreHeight = 0) = 0; + NetworkType nettype = MAINNET, uint64_t restoreHeight = 0, uint64_t kdf_rounds = 1) = 0; Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, bool testnet = false, uint64_t restoreHeight = 0) // deprecated { @@ -977,6 +986,7 @@ struct WalletManager * \param addressString public address * \param viewKeyString view key * \param spendKeyString spend key (optional) + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * createWalletFromKeys(const std::string &path, @@ -986,7 +996,8 @@ struct WalletManager uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString = "") = 0; + const std::string &spendKeyString = "", + uint64_t kdf_rounds = 1) = 0; Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, @@ -1037,6 +1048,7 @@ struct WalletManager * \param deviceName Device name * \param restoreHeight restore from start height (0 sets to current height) * \param subaddressLookahead Size of subaddress lookahead (empty sets to some default low value) + * \param kdf_rounds Number of rounds for key derivation function * \return Wallet instance (Wallet::status() needs to be called to check if recovered successfully) */ virtual Wallet * createWalletFromDevice(const std::string &path, @@ -1044,7 +1056,8 @@ struct WalletManager NetworkType nettype, const std::string &deviceName, uint64_t restoreHeight = 0, - const std::string &subaddressLookahead = "") = 0; + const std::string &subaddressLookahead = "", + uint64_t kdf_rounds = 1) = 0; /*! * \brief Closes wallet. In case operation succeeded, wallet object deleted. in case operation failed, wallet object not deleted @@ -1069,9 +1082,14 @@ struct WalletManager * @param keys_file_name - location of keys file * @param password - password to verify * @param no_spend_key - verify only view keys? + * @param kdf_rounds - number of rounds for key derivation function * @return - true if password is correct + * + * @note + * This function will fail when the wallet keys file is opened because the wallet program locks the keys file. + * In this case, Wallet::unlockKeysFile() and Wallet::lockKeysFile() need to be called before and after the call to this function, respectively. */ - virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const = 0; + virtual bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const = 0; /*! * \brief findWallets - searches for the wallet files by given path name recursively diff --git a/src/wallet/api/wallet_manager.cpp b/src/wallet/api/wallet_manager.cpp index 99eadc82f..5daf11ec0 100644 --- a/src/wallet/api/wallet_manager.cpp +++ b/src/wallet/api/wallet_manager.cpp @@ -50,16 +50,16 @@ namespace epee { namespace Monero { Wallet *WalletManagerImpl::createWallet(const std::string &path, const std::string &password, - const std::string &language, NetworkType nettype) + const std::string &language, NetworkType nettype, uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds); wallet->create(path, password, language); return wallet; } -Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype) +Wallet *WalletManagerImpl::openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds); wallet->open(path, password); //Refresh addressBook wallet->addressBook()->refresh(); @@ -87,9 +87,10 @@ Wallet *WalletManagerImpl::recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, NetworkType nettype, - uint64_t restoreHeight) + uint64_t restoreHeight, + uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -104,9 +105,10 @@ Wallet *WalletManagerImpl::createWalletFromKeys(const std::string &path, uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString) + const std::string &spendKeyString, + uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -119,9 +121,10 @@ Wallet *WalletManagerImpl::createWalletFromDevice(const std::string &path, NetworkType nettype, const std::string &deviceName, uint64_t restoreHeight, - const std::string &subaddressLookahead) + const std::string &subaddressLookahead, + uint64_t kdf_rounds) { - WalletImpl * wallet = new WalletImpl(nettype); + WalletImpl * wallet = new WalletImpl(nettype, false, kdf_rounds); if(restoreHeight > 0){ wallet->setRefreshFromBlockHeight(restoreHeight); } @@ -159,9 +162,9 @@ bool WalletManagerImpl::walletExists(const std::string &path) return false; } -bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const +bool WalletManagerImpl::verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds) const { - return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default")); + return tools::wallet2::verify_password(keys_file_name, password, no_spend_key, hw::get_device("default"), kdf_rounds); } std::vector<std::string> WalletManagerImpl::findWallets(const std::string &path) diff --git a/src/wallet/api/wallet_manager.h b/src/wallet/api/wallet_manager.h index 656a7142c..8b1c8be7f 100644 --- a/src/wallet/api/wallet_manager.h +++ b/src/wallet/api/wallet_manager.h @@ -39,13 +39,14 @@ class WalletManagerImpl : public WalletManager { public: Wallet * createWallet(const std::string &path, const std::string &password, - const std::string &language, NetworkType nettype) override; - Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype) override; + const std::string &language, NetworkType nettype, uint64_t kdf_rounds = 1) override; + Wallet * openWallet(const std::string &path, const std::string &password, NetworkType nettype, uint64_t kdf_rounds = 1) override; virtual Wallet * recoveryWallet(const std::string &path, const std::string &password, const std::string &mnemonic, NetworkType nettype, - uint64_t restoreHeight) override; + uint64_t restoreHeight, + uint64_t kdf_rounds = 1) override; virtual Wallet * createWalletFromKeys(const std::string &path, const std::string &password, const std::string &language, @@ -53,7 +54,8 @@ public: uint64_t restoreHeight, const std::string &addressString, const std::string &viewKeyString, - const std::string &spendKeyString = "") override; + const std::string &spendKeyString = "", + uint64_t kdf_rounds = 1) override; // next two methods are deprecated - use the above version which allow setting of a password virtual Wallet * recoveryWallet(const std::string &path, const std::string &mnemonic, NetworkType nettype, uint64_t restoreHeight) override; // deprecated: use createWalletFromKeys(..., password, ...) instead @@ -69,10 +71,11 @@ public: NetworkType nettype, const std::string &deviceName, uint64_t restoreHeight = 0, - const std::string &subaddressLookahead = "") override; + const std::string &subaddressLookahead = "", + uint64_t kdf_rounds = 1) override; virtual bool closeWallet(Wallet *wallet, bool store = true) override; bool walletExists(const std::string &path) override; - bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key) const override; + bool verifyWalletPassword(const std::string &keys_file_name, const std::string &password, bool no_spend_key, uint64_t kdf_rounds = 1) const override; std::vector<std::string> findWallets(const std::string &path) override; std::string errorString() const override; void setDaemonAddress(const std::string &address) override; diff --git a/src/wallet/node_rpc_proxy.cpp b/src/wallet/node_rpc_proxy.cpp index c5d869354..401ada61b 100644 --- a/src/wallet/node_rpc_proxy.cpp +++ b/src/wallet/node_rpc_proxy.cpp @@ -41,21 +41,13 @@ static const std::chrono::seconds rpc_timeout = std::chrono::minutes(3) + std::c NodeRPCProxy::NodeRPCProxy(epee::net_utils::http::http_simple_client &http_client, boost::mutex &mutex) : m_http_client(http_client) , m_daemon_rpc_mutex(mutex) - , m_height(0) - , m_height_time(0) - , m_earliest_height() - , m_dynamic_per_kb_fee_estimate(0) - , m_dynamic_per_kb_fee_estimate_cached_height(0) - , m_dynamic_per_kb_fee_estimate_grace_blocks(0) - , m_rpc_version(0) - , m_target_height(0) - , m_target_height_time(0) -{} +{ + invalidate(); +} void NodeRPCProxy::invalidate() { m_height = 0; - m_height_time = 0; for (size_t n = 0; n < 256; ++n) m_earliest_height[n] = 0; m_dynamic_per_kb_fee_estimate = 0; @@ -63,7 +55,8 @@ void NodeRPCProxy::invalidate() m_dynamic_per_kb_fee_estimate_grace_blocks = 0; m_rpc_version = 0; m_target_height = 0; - m_target_height_time = 0; + m_block_size_limit = 0; + m_get_info_time = 0; } boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version) const @@ -84,36 +77,15 @@ boost::optional<std::string> NodeRPCProxy::get_rpc_version(uint32_t &rpc_version return boost::optional<std::string>(); } -boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const -{ - const time_t now = time(NULL); - if (m_height == 0 || now >= m_height_time + 30) // re-cache every 30 seconds - { - cryptonote::COMMAND_RPC_GET_HEIGHT::request req = AUTO_VAL_INIT(req); - cryptonote::COMMAND_RPC_GET_HEIGHT::response res = AUTO_VAL_INIT(res); - - m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_json("/getheight", req, res, m_http_client, rpc_timeout); - m_daemon_rpc_mutex.unlock(); - CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status != CORE_RPC_STATUS_BUSY, res.status, "Failed to connect to daemon"); - CHECK_AND_ASSERT_MES(res.status == CORE_RPC_STATUS_OK, res.status, "Failed to get current blockchain height"); - m_height = res.height; - m_height_time = now; - } - height = m_height; - return boost::optional<std::string>(); -} - void NodeRPCProxy::set_height(uint64_t h) { m_height = h; } -boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const +boost::optional<std::string> NodeRPCProxy::get_info() const { const time_t now = time(NULL); - if (m_target_height == 0 || now >= m_target_height_time + 30) // re-cache every 30 seconds + if (now >= m_get_info_time + 30) // re-cache every 30 seconds { cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t); @@ -125,13 +97,41 @@ boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) c CHECK_AND_ASSERT_MES(r, std::string(), "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status != CORE_RPC_STATUS_BUSY, resp_t.status, "Failed to connect to daemon"); CHECK_AND_ASSERT_MES(resp_t.status == CORE_RPC_STATUS_OK, resp_t.status, "Failed to get target blockchain height"); + m_height = resp_t.height; m_target_height = resp_t.target_height; - m_target_height_time = now; + m_block_size_limit = resp_t.block_size_limit; + m_get_info_time = now; } + return boost::optional<std::string>(); +} + +boost::optional<std::string> NodeRPCProxy::get_height(uint64_t &height) const +{ + auto res = get_info(); + if (res) + return res; + height = m_height; + return boost::optional<std::string>(); +} + +boost::optional<std::string> NodeRPCProxy::get_target_height(uint64_t &height) const +{ + auto res = get_info(); + if (res) + return res; height = m_target_height; return boost::optional<std::string>(); } +boost::optional<std::string> NodeRPCProxy::get_block_size_limit(uint64_t &block_size_limit) const +{ + auto res = get_info(); + if (res) + return res; + block_size_limit = m_block_size_limit; + return boost::optional<std::string>(); +} + boost::optional<std::string> NodeRPCProxy::get_earliest_height(uint8_t version, uint64_t &earliest_height) const { if (m_earliest_height[version] == 0) diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h index 1b183212d..8a65884f7 100644 --- a/src/wallet/node_rpc_proxy.h +++ b/src/wallet/node_rpc_proxy.h @@ -47,22 +47,25 @@ public: boost::optional<std::string> get_height(uint64_t &height) const; void set_height(uint64_t h); boost::optional<std::string> get_target_height(uint64_t &height) const; + boost::optional<std::string> get_block_size_limit(uint64_t &block_size_limit) const; boost::optional<std::string> get_earliest_height(uint8_t version, uint64_t &earliest_height) const; boost::optional<std::string> get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const; private: + boost::optional<std::string> get_info() const; + epee::net_utils::http::http_simple_client &m_http_client; boost::mutex &m_daemon_rpc_mutex; mutable uint64_t m_height; - mutable time_t m_height_time; mutable uint64_t m_earliest_height[256]; mutable uint64_t m_dynamic_per_kb_fee_estimate; mutable uint64_t m_dynamic_per_kb_fee_estimate_cached_height; mutable uint64_t m_dynamic_per_kb_fee_estimate_grace_blocks; mutable uint32_t m_rpc_version; mutable uint64_t m_target_height; - mutable time_t m_target_height_time; + mutable uint64_t m_block_size_limit; + mutable time_t m_get_info_time; }; } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d99371673..52642cf82 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -160,6 +160,7 @@ struct options { return val; } }; + const command_line::arg_descriptor<uint64_t> kdf_rounds = {"kdf-rounds", tools::wallet2::tr("Number of rounds for the key derivation function"), 1}; }; void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file) @@ -203,6 +204,8 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl const bool stagenet = command_line::get_arg(vm, opts.stagenet); const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; const bool restricted = command_line::get_arg(vm, opts.restricted); + const uint64_t kdf_rounds = command_line::get_arg(vm, opts.kdf_rounds); + THROW_WALLET_EXCEPTION_IF(kdf_rounds == 0, tools::error::wallet_internal_error, "KDF rounds must not be 0"); auto daemon_address = command_line::get_arg(vm, opts.daemon_address); auto daemon_host = command_line::get_arg(vm, opts.daemon_host); @@ -236,7 +239,7 @@ std::unique_ptr<tools::wallet2> make_basic(const boost::program_options::variabl if (daemon_address.empty()) daemon_address = std::string("http://") + daemon_host + ":" + std::to_string(daemon_port); - std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, restricted)); + std::unique_ptr<tools::wallet2> wallet(new tools::wallet2(nettype, restricted, kdf_rounds)); wallet->init(std::move(daemon_address), std::move(login)); boost::filesystem::path ringdb_path = command_line::get_arg(vm, opts.shared_ringdb_dir); wallet->set_ring_database(ringdb_path.string()); @@ -647,7 +650,7 @@ const size_t MAX_SPLIT_ATTEMPTS = 30; constexpr const std::chrono::seconds wallet2::rpc_timeout; const char* wallet2::tr(const char* str) { return i18n_translate(str, "tools::wallet2"); } -wallet2::wallet2(network_type nettype, bool restricted): +wallet2::wallet2(network_type nettype, bool restricted, uint64_t kdf_rounds): m_multisig_rescan_info(NULL), m_multisig_rescan_k(NULL), m_run(true), @@ -676,8 +679,10 @@ wallet2::wallet2(network_type nettype, bool restricted): m_segregate_pre_fork_outputs(true), m_key_reuse_mitigation2(true), m_segregation_height(0), + m_ignore_fractional_outputs(true), m_is_initialized(false), m_restricted(restricted), + m_kdf_rounds(kdf_rounds), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex), m_subaddress_lookahead_major(SUBADDRESS_LOOKAHEAD_MAJOR), @@ -722,6 +727,7 @@ void wallet2::init_options(boost::program_options::options_description& desc_par command_line::add_arg(desc_params, opts.stagenet); command_line::add_arg(desc_params, opts.restricted); command_line::add_arg(desc_params, opts.shared_ringdb_dir); + command_line::add_arg(desc_params, opts.kdf_rounds); } std::unique_ptr<wallet2> wallet2::make_from_json(const boost::program_options::variables_map& vm, const std::string& json_file, const std::function<boost::optional<tools::password_container>(const char *, bool)> &password_prompter) @@ -1057,6 +1063,16 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio tx_scan_info.error = false; } //---------------------------------------------------------------------------------------------------- +void wallet2::check_acc_out_precomp_once(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const +{ + tx_scan_info.received = boost::none; + if (already_seen) + return; + check_acc_out_precomp(o, derivation, additional_derivations, i, is_out_data, tx_scan_info); + if (tx_scan_info.received) + already_seen = true; +} +//---------------------------------------------------------------------------------------------------- static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev) { crypto::secret_key scalar1; @@ -1173,7 +1189,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // Don't try to extract tx public key if tx has no ouputs size_t pk_index = 0; std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size()); - std::unordered_set<crypto::public_key> public_keys_seen; + std::deque<bool> output_found(tx.vout.size(), false); while (!tx.vout.empty()) { // if tx.vout is not empty, we loop through all tx pubkeys @@ -1194,13 +1210,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote error::wallet_internal_error, "tx_cache_data is out of sync"); } - if (public_keys_seen.find(pub_key_field.pub_key) != public_keys_seen.end()) - { - MWARNING("The same transaction pubkey is present more than once, ignoring extra instance"); - continue; - } - public_keys_seen.insert(pub_key_field.pub_key); - int num_vouts_received = 0; tx_pub_key = pub_key_field.pub_key; tools::threadpool& tpool = tools::threadpool::getInstance(); @@ -1264,7 +1273,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase) { - check_acc_out_precomp(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0]); + check_acc_out_precomp_once(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0], output_found[0]); THROW_WALLET_EXCEPTION_IF(tx_scan_info[0].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); // this assumes that the miner tx pays a single address @@ -1274,8 +1283,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote // the first one was already checked for (size_t i = 1; i < tx.vout.size(); ++i) { - tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, - std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true); + tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, + std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true); } waiter.wait(&tpool); // then scan all outputs from 0 @@ -1297,8 +1306,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { for (size_t i = 0; i < tx.vout.size(); ++i) { - tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, - std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true); + tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i, + std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true); } waiter.wait(&tpool); @@ -1319,7 +1328,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { for (size_t i = 0; i < tx.vout.size(); ++i) { - check_acc_out_precomp(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i]); + check_acc_out_precomp_once(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i], output_found[i]); THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { @@ -1553,6 +1562,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote { // We got a payment ID to go with this tx LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8); + MINFO("Consider using subaddresses instead of encrypted payment IDs"); if (tx_pub_key != null_pkey) { if (!m_account.get_device().decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key)) @@ -1576,12 +1586,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) { LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); + MWARNING("Found unencrypted payment ID: these are bad for privacy, consider using subaddresses instead"); } } - else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) - { - LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); - } for (const auto& i : tx_money_got_in_outs) { @@ -1820,7 +1827,7 @@ void wallet2::process_parsed_blocks(uint64_t start_height, const std::vector<cry blocks_added = 0; THROW_WALLET_EXCEPTION_IF(blocks.size() != parsed_blocks.size(), error::wallet_internal_error, "size mismatch"); - THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::wallet_internal_error, "Index out of bounds of hashchain"); + THROW_WALLET_EXCEPTION_IF(!m_blockchain.is_in_bounds(current_index), error::out_of_hashchain_bounds_error); tools::threadpool& tpool = tools::threadpool::getInstance(); tools::threadpool::waiter waiter; @@ -2052,8 +2059,8 @@ void wallet2::update_pool_state(bool refreshed) MDEBUG("update_pool_state start"); // get the pool state - cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request req; - cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response res; + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::request req; + cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL_HASHES_BIN::response res; m_daemon_rpc_mutex.lock(); bool r = epee::net_utils::invoke_http_json("/get_transaction_pool_hashes.bin", req, res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); @@ -2266,12 +2273,12 @@ void wallet2::update_pool_state(bool refreshed) MDEBUG("update_pool_state end"); } //---------------------------------------------------------------------------------------------------- -void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history) +void wallet2::fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force) { std::vector<crypto::hash> hashes; const uint64_t checkpoint_height = m_checkpoints.get_max_height(); - if (stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) + if ((stop_height > checkpoint_height && m_blockchain.size()-1 < checkpoint_height) && !force) { // we will drop all these, so don't bother getting them uint64_t missing_blocks = m_checkpoints.get_max_height() - m_blockchain.size(); @@ -2436,6 +2443,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo std::vector<cryptonote::block_complete_entry> next_blocks; std::vector<parsed_block> next_parsed_blocks; bool error = false; + added_blocks = 0; if (!first && blocks.empty()) { refreshed = false; @@ -2445,7 +2453,33 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo if (!first) { - process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks); + try + { + process_parsed_blocks(blocks_start_height, blocks, parsed_blocks, added_blocks); + } + catch (const tools::error::out_of_hashchain_bounds_error&) + { + MINFO("Daemon claims next refresh block is out of hash chain bounds, resetting hash chain"); + uint64_t stop_height = m_blockchain.offset(); + std::vector<crypto::hash> tip(m_blockchain.size() - m_blockchain.offset()); + for (size_t i = m_blockchain.offset(); i < m_blockchain.size(); ++i) + tip[i - m_blockchain.offset()] = m_blockchain[i]; + cryptonote::block b; + generate_genesis(b); + m_blockchain.clear(); + m_blockchain.push_back(get_block_hash(b)); + short_chain_history.clear(); + get_short_chain_history(short_chain_history); + fast_refresh(stop_height, blocks_start_height, short_chain_history, true); + THROW_WALLET_EXCEPTION_IF(m_blockchain.size() != stop_height, error::wallet_internal_error, "Unexpected hashchain size"); + THROW_WALLET_EXCEPTION_IF(m_blockchain.offset() != 0, error::wallet_internal_error, "Unexpected hashchain offset"); + for (const auto &h: tip) + m_blockchain.push_back(h); + short_chain_history.clear(); + get_short_chain_history(short_chain_history); + start_height = stop_height; + throw std::runtime_error(""); // loop again + } blocks_fetched += added_blocks; } waiter.wait(&tpool); @@ -2475,6 +2509,7 @@ void wallet2::refresh(bool trusted_daemon, uint64_t start_height, uint64_t & blo if(try_count < 3) { LOG_PRINT_L1("Another try pull_blocks (try_count=" << try_count << ")..."); + first = true; ++try_count; } else @@ -2517,7 +2552,7 @@ bool wallet2::refresh(bool trusted_daemon, uint64_t & blocks_fetched, bool& rece return ok; } //---------------------------------------------------------------------------------------------------- -bool wallet2::get_output_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution) +bool wallet2::get_rct_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution) { uint32_t rpc_version; boost::optional<std::string> result = m_node_rpc_proxy.get_rpc_version(rpc_version); @@ -2651,7 +2686,7 @@ void wallet2::detach_blockchain(uint64_t height) bool wallet2::deinit() { m_is_initialized=false; - m_keys_file_locker.reset(); + unlock_keys_file(); return true; } //---------------------------------------------------------------------------------------------------- @@ -2797,6 +2832,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable value2.SetUint(m_segregation_height); json.AddMember("segregation_height", value2, json.GetAllocator()); + value2.SetInt(m_ignore_fractional_outputs ? 1 : 0); + json.AddMember("ignore_fractional_outputs", value2, json.GetAllocator()); + value2.SetUint(m_subaddress_lookahead_major); json.AddMember("subaddress_lookahead_major", value2, json.GetAllocator()); @@ -2811,19 +2849,19 @@ bool wallet2::store_keys(const std::string& keys_file_name, const epee::wipeable // Encrypt the entire JSON object. crypto::chacha_key key; - crypto::generate_chacha_key(password.data(), password.size(), key); + crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds); std::string cipher; cipher.resize(account_data.size()); keys_file_data.iv = crypto::rand<crypto::chacha_iv>(); crypto::chacha20(account_data.data(), account_data.size(), key, keys_file_data.iv, &cipher[0]); keys_file_data.account_data = cipher; - m_keys_file_locker.reset(); + unlock_keys_file(); std::string buf; r = ::serialization::dump_binary(keys_file_data, buf); r = r && epee::file_io_utils::save_string_to_file(keys_file_name, buf); //and never touch wallet_keys_file again, only read CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << keys_file_name); - m_keys_file_locker.reset(new tools::file_locker(m_keys_file)); + lock_keys_file(); return true; } @@ -2845,7 +2883,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ r = ::serialization::parse_binary(buf, keys_file_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); crypto::chacha_key key; - crypto::generate_chacha_key(password.data(), password.size(), key); + crypto::generate_chacha_key(password.data(), password.size(), key, m_kdf_rounds); std::string account_data; account_data.resize(keys_file_data.account_data.size()); crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); @@ -2879,6 +2917,7 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_segregate_pre_fork_outputs = true; m_key_reuse_mitigation2 = true; m_segregation_height = 0; + m_ignore_fractional_outputs = true; m_subaddress_lookahead_major = SUBADDRESS_LOOKAHEAD_MAJOR; m_subaddress_lookahead_minor = SUBADDRESS_LOOKAHEAD_MINOR; m_key_on_device = false; @@ -3005,6 +3044,8 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ m_key_reuse_mitigation2 = field_key_reuse_mitigation2; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, segregation_height, int, Uint, false, 0); m_segregation_height = field_segregation_height; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, ignore_fractional_outputs, int, Int, false, true); + m_ignore_fractional_outputs = field_ignore_fractional_outputs; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_major, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MAJOR); m_subaddress_lookahead_major = field_subaddress_lookahead_major; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, subaddress_lookahead_minor, uint32_t, Uint, false, SUBADDRESS_LOOKAHEAD_MINOR); @@ -3044,9 +3085,13 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_ * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password * */ -bool wallet2::verify_password(const epee::wipeable_string& password) const +bool wallet2::verify_password(const epee::wipeable_string& password) { - return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device()); + // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded). + unlock_keys_file(); + bool r = verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device(), m_kdf_rounds); + lock_keys_file(); + return r; } /*! @@ -3062,7 +3107,7 @@ bool wallet2::verify_password(const epee::wipeable_string& password) const * can be used prior to rewriting wallet keys file, to ensure user has entered the correct password * */ -bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev) +bool wallet2::verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds) { rapidjson::Document json; wallet2::keys_file_data keys_file_data; @@ -3074,7 +3119,7 @@ bool wallet2::verify_password(const std::string& keys_file_name, const epee::wip r = ::serialization::parse_binary(buf, keys_file_data); THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + keys_file_name + '\"'); crypto::chacha_key key; - crypto::generate_chacha_key(password.data(), password.size(), key); + crypto::generate_chacha_key(password.data(), password.size(), key, kdf_rounds); std::string account_data; account_data.resize(keys_file_data.account_data.size()); crypto::chacha20(keys_file_data.account_data.data(), keys_file_data.account_data.size(), key, keys_file_data.iv, &account_data[0]); @@ -3942,7 +3987,7 @@ bool wallet2::check_connection(uint32_t *version, uint32_t timeout) bool wallet2::generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const { hw::device &hwdev = m_account.get_device(); - return hwdev.generate_chacha_key(m_account.get_keys(), key); + return hwdev.generate_chacha_key(m_account.get_keys(), key, m_kdf_rounds); } //---------------------------------------------------------------------------------------------------- void wallet2::load(const std::string& wallet_, const epee::wipeable_string& password) @@ -3953,17 +3998,17 @@ void wallet2::load(const std::string& wallet_, const epee::wipeable_string& pass boost::system::error_code e; bool exists = boost::filesystem::exists(m_keys_file, e); THROW_WALLET_EXCEPTION_IF(e || !exists, error::file_not_found, m_keys_file); - m_keys_file_locker.reset(new tools::file_locker(m_keys_file)); - THROW_WALLET_EXCEPTION_IF(!m_keys_file_locker->locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program"); + lock_keys_file(); + THROW_WALLET_EXCEPTION_IF(!is_keys_file_locked(), error::wallet_internal_error, "internal error: \"" + m_keys_file + "\" is opened by another wallet program"); // this temporary unlocking is necessary for Windows (otherwise the file couldn't be loaded). - m_keys_file_locker.reset(); + unlock_keys_file(); if (!load_keys(m_keys_file, password)) { THROW_WALLET_EXCEPTION_IF(true, error::file_read_error, m_keys_file); } LOG_PRINT_L0("Loaded wallet keys file, with public address: " << m_account.get_public_address_str(m_nettype)); - m_keys_file_locker.reset(new tools::file_locker(m_keys_file)); + lock_keys_file(); //keys loaded ok! //try to load wallet file. but even if we failed, it is not big problem @@ -5615,15 +5660,10 @@ uint32_t wallet2::adjust_priority(uint32_t priority) } // get the current full reward zone - cryptonote::COMMAND_RPC_GET_INFO::request getinfo_req = AUTO_VAL_INIT(getinfo_req); - cryptonote::COMMAND_RPC_GET_INFO::response getinfo_res = AUTO_VAL_INIT(getinfo_res); - m_daemon_rpc_mutex.lock(); - bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", getinfo_req, getinfo_res, m_http_client); - m_daemon_rpc_mutex.unlock(); - THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info"); - THROW_WALLET_EXCEPTION_IF(getinfo_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info"); - THROW_WALLET_EXCEPTION_IF(getinfo_res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error); - const uint64_t full_reward_zone = getinfo_res.block_size_limit / 2; + uint64_t block_size_limit = 0; + const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit); + throw_on_rpc_response_error(result, "get_info"); + const uint64_t full_reward_zone = block_size_limit / 2; // get the last N block headers and sum the block sizes const size_t N = 10; @@ -5637,7 +5677,7 @@ uint32_t wallet2::adjust_priority(uint32_t priority) m_daemon_rpc_mutex.lock(); getbh_req.start_height = m_blockchain.size() - N; getbh_req.end_height = m_blockchain.size() - 1; - r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout); + bool r = net_utils::invoke_http_json_rpc("/json_rpc", "getblockheadersrange", getbh_req, getbh_res, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "getblockheadersrange"); THROW_WALLET_EXCEPTION_IF(getbh_res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "getblockheadersrange"); @@ -6004,6 +6044,33 @@ bool wallet2::is_output_blackballed(const crypto::public_key &output) const catch (const std::exception &e) { return false; } } +bool wallet2::lock_keys_file() +{ + if (m_keys_file_locker) + { + MDEBUG(m_keys_file << " is already locked."); + return false; + } + m_keys_file_locker.reset(new tools::file_locker(m_keys_file)); + return true; +} + +bool wallet2::unlock_keys_file() +{ + if (!m_keys_file_locker) + { + MDEBUG(m_keys_file << " is already unlocked."); + return false; + } + m_keys_file_locker.reset(); + return true; +} + +bool wallet2::is_keys_file_locked() const +{ + return m_keys_file_locker->locked(); +} + bool wallet2::tx_add_fake_output(std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, uint64_t global_index, const crypto::public_key& output_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const { if (!unlocked) // don't add locked outs @@ -6144,22 +6211,42 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> bool is_shortly_after_segregation_fork = height >= segregation_fork_height && height < segregation_fork_height + SEGREGATION_FORK_VICINITY; bool is_after_segregation_fork = height >= segregation_fork_height; + // if we have at least one rct out, get the distribution, or fall back to the previous system + uint64_t rct_start_height; + std::vector<uint64_t> rct_offsets; + bool has_rct = false; + for (size_t idx: selected_transfers) + if (m_transfers[idx].is_rct()) + { has_rct = true; break; } + const bool has_rct_distribution = has_rct && get_rct_distribution(rct_start_height, rct_offsets); + if (has_rct_distribution) + { + // check we're clear enough of rct start, to avoid corner cases below + THROW_WALLET_EXCEPTION_IF(rct_offsets.size() <= CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE, + error::get_output_distribution, "Not enough rct outputs"); + } + // get histogram for the amounts we need cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t); - m_daemon_rpc_mutex.lock(); + // request histogram for all outputs, except 0 if we have the rct distribution for(size_t idx: selected_transfers) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); - std::sort(req_t.amounts.begin(), req_t.amounts.end()); - auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end()); - req_t.amounts.resize(std::distance(req_t.amounts.begin(), end)); - req_t.unlocked = true; - req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE; - bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout); - m_daemon_rpc_mutex.unlock(); - THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected"); - THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); - THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status); + if (!m_transfers[idx].is_rct() || !has_rct_distribution) + req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); + if (!req_t.amounts.empty()) + { + std::sort(req_t.amounts.begin(), req_t.amounts.end()); + auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end()); + req_t.amounts.resize(std::distance(req_t.amounts.begin(), end)); + req_t.unlocked = true; + req_t.recent_cutoff = time(NULL) - RECENT_OUTPUT_ZONE; + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "transfer_selected"); + THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_output_histogram"); + THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_histogram_error, resp_t.status); + } // if we want to segregate fake outs pre or post fork, get distribution std::unordered_map<uint64_t, std::pair<uint64_t, uint64_t>> segregation_limit; @@ -6215,6 +6302,36 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> COMMAND_RPC_GET_OUTPUTS_BIN::request req = AUTO_VAL_INIT(req); COMMAND_RPC_GET_OUTPUTS_BIN::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + struct gamma_engine + { + typedef uint64_t result_type; + static constexpr result_type min() { return 0; } + static constexpr result_type max() { return std::numeric_limits<result_type>::max(); } + result_type operator()() { return crypto::rand<result_type>(); } + } engine; + static const double shape = 19.28/*16.94*/; + //static const double shape = m_testnet ? 17.02 : 17.28; + static const double scale = 1/1.61; + std::gamma_distribution<double> gamma(shape, scale); + auto pick_gamma = [&]() + { + double x = gamma(engine); + x = exp(x); + uint64_t block_offset = x / DIFFICULTY_TARGET_V2; // this assumes constant target over the whole rct range + if (block_offset >= rct_offsets.size() - 1) + return std::numeric_limits<uint64_t>::max(); // bad pick + block_offset = rct_offsets.size() - 2 - block_offset; + THROW_WALLET_EXCEPTION_IF(block_offset >= rct_offsets.size() - 1, error::wallet_internal_error, "Bad offset calculation"); + THROW_WALLET_EXCEPTION_IF(rct_offsets[block_offset + 1] < rct_offsets[block_offset], + error::get_output_distribution, "Decreasing offsets in rct distribution: " + + std::to_string(block_offset) + ": " + std::to_string(rct_offsets[block_offset]) + ", " + + std::to_string(block_offset + 1) + ": " + std::to_string(rct_offsets[block_offset + 1])); + uint64_t n_rct = rct_offsets[block_offset + 1] - rct_offsets[block_offset]; + if (n_rct == 0) + return rct_offsets[block_offset] ? rct_offsets[block_offset] - 1 : 0; + return rct_offsets[block_offset] + crypto::rand<uint64_t>() % n_rct; + }; + size_t num_selected_transfers = 0; for(size_t idx: selected_transfers) { @@ -6225,6 +6342,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> // request more for rct in base recent (locked) coinbases are picked, since they're locked for longer size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); size_t start = req.outputs.size(); + bool use_histogram = amount != 0 || !has_rct_distribution; const bool output_is_pre_fork = td.m_block_height < segregation_fork_height; uint64_t num_outs = 0, num_recent_outs = 0; @@ -6280,26 +6398,41 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> num_post_fork_outs = num_outs - segregation_limit[amount].first; } - LOG_PRINT_L1("" << num_outs << " unlocked outputs of size " << print_money(amount)); - THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, - "histogram reports no unlocked outputs for " + boost::lexical_cast<std::string>(amount) + ", not even ours"); - THROW_WALLET_EXCEPTION_IF(num_recent_outs > num_outs, error::wallet_internal_error, - "histogram reports more recent outs than outs for " + boost::lexical_cast<std::string>(amount)); + if (use_histogram) + { + LOG_PRINT_L1("" << num_outs << " unlocked outputs of size " << print_money(amount)); + THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, + "histogram reports no unlocked outputs for " + boost::lexical_cast<std::string>(amount) + ", not even ours"); + THROW_WALLET_EXCEPTION_IF(num_recent_outs > num_outs, error::wallet_internal_error, + "histogram reports more recent outs than outs for " + boost::lexical_cast<std::string>(amount)); + } + else + { + // the base offset of the first rct output in the first unlocked block (or the one to be if there's none) + num_outs = rct_offsets[rct_offsets.size() - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE]; + LOG_PRINT_L1("" << num_outs << " unlocked rct outputs"); + THROW_WALLET_EXCEPTION_IF(num_outs == 0, error::wallet_internal_error, + "histogram reports no unlocked rct outputs, not even ours"); + } - // how many fake outs to draw on a pre-fork triangular distribution + // how many fake outs to draw on a pre-fork distribution size_t pre_fork_outputs_count = requested_outputs_count * pre_fork_num_out_ratio; size_t post_fork_outputs_count = requested_outputs_count * post_fork_num_out_ratio; // how many fake outs to draw otherwise size_t normal_output_count = requested_outputs_count - pre_fork_outputs_count - post_fork_outputs_count; - // X% of those outs are to be taken from recent outputs - size_t recent_outputs_count = normal_output_count * RECENT_OUTPUT_RATIO; - if (recent_outputs_count == 0) - recent_outputs_count = 1; // ensure we have at least one, if possible - if (recent_outputs_count > num_recent_outs) - recent_outputs_count = num_recent_outs; - if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) - --recent_outputs_count; // if the real out is recent, pick one less recent fake out + size_t recent_outputs_count = 0; + if (use_histogram) + { + // X% of those outs are to be taken from recent outputs + recent_outputs_count = normal_output_count * RECENT_OUTPUT_RATIO; + if (recent_outputs_count == 0) + recent_outputs_count = 1; // ensure we have at least one, if possible + if (recent_outputs_count > num_recent_outs) + recent_outputs_count = num_recent_outs; + if (td.m_global_output_index >= num_outs - num_recent_outs && recent_outputs_count > 0) + --recent_outputs_count; // if the real out is recent, pick one less recent fake out + } LOG_PRINT_L1("Fake output makeup: " << requested_outputs_count << " requested: " << recent_outputs_count << " recent, " << pre_fork_outputs_count << " pre-fork, " << post_fork_outputs_count << " post-fork, " << (requested_outputs_count - recent_outputs_count - pre_fork_outputs_count - post_fork_outputs_count) << " full-chain"); @@ -6379,7 +6512,26 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> uint64_t i; const char *type = ""; - if (num_found - 1 < recent_outputs_count) // -1 to account for the real one we seeded with + if (amount == 0 && has_rct_distribution) + { + // gamma distribution + if (num_found -1 < recent_outputs_count + pre_fork_outputs_count) + { + do i = pick_gamma(); while (i >= segregation_limit[amount].first); + type = "pre-fork gamma"; + } + else if (num_found -1 < recent_outputs_count + pre_fork_outputs_count + post_fork_outputs_count) + { + do i = pick_gamma(); while (i < segregation_limit[amount].first || i >= num_outs); + type = "post-fork gamma"; + } + else + { + do i = pick_gamma(); while (i >= num_outs); + type = "gamma"; + } + } + else if (num_found - 1 < recent_outputs_count) // -1 to account for the real one we seeded with { // triangular distribution over [a,b) with a=0, mode c=b=up_index_limit uint64_t r = crypto::rand<uint64_t>() % ((uint64_t)1 << 53); @@ -6444,7 +6596,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> // get the keys for those m_daemon_rpc_mutex.lock(); - r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); + bool r = epee::net_utils::invoke_http_bin("/get_outs.bin", req, daemon_resp, m_http_client, rpc_timeout); m_daemon_rpc_mutex.unlock(); THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_outs.bin"); THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_outs.bin"); @@ -7688,12 +7840,24 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp for (uint32_t i : subaddr_indices) LOG_PRINT_L2("Candidate subaddress index for spending: " << i); + // determine threshold for fractional amount + const size_t tx_size_one_ring = estimate_tx_size(use_rct, 1, fake_outs_count, 2, 0, bulletproof); + const size_t tx_size_two_rings = estimate_tx_size(use_rct, 2, fake_outs_count, 2, 0, bulletproof); + THROW_WALLET_EXCEPTION_IF(tx_size_one_ring > tx_size_two_rings, error::wallet_internal_error, "Estimated tx size with 1 input is larger than with 2 inputs!"); + const size_t tx_size_per_ring = tx_size_two_rings - tx_size_one_ring; + const uint64_t fractional_threshold = (fee_multiplier * fee_per_kb * tx_size_per_ring) / 1024; + // gather all dust and non-dust outputs belonging to specified subaddresses size_t num_nondust_outputs = 0; size_t num_dust_outputs = 0; for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; + if (m_ignore_fractional_outputs && td.amount() < fractional_threshold) + { + MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold)); + continue; + } if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) { const uint32_t index_minor = td.m_subaddr_index.minor; @@ -9399,31 +9563,15 @@ uint64_t wallet2::get_daemon_blockchain_height(string &err) const uint64_t wallet2::get_daemon_blockchain_target_height(string &err) { - cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t); - cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t); - m_daemon_rpc_mutex.lock(); - bool ok = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client); - m_daemon_rpc_mutex.unlock(); - if (ok) - { - if (resp_t.status == CORE_RPC_STATUS_BUSY) - { - err = "daemon is busy. Please try again later."; - } - else if (resp_t.status != CORE_RPC_STATUS_OK) - { - err = resp_t.status; - } - else // success, cleaning up error message - { - err = ""; - } - } - else + err = ""; + uint64_t target_height = 0; + const auto result = m_node_rpc_proxy.get_target_height(target_height); + if (result && *result != CORE_RPC_STATUS_OK) { - err = "possibly lost connection to daemon"; + err= *result; + return 0; } - return resp_t.target_height; + return target_height; } uint64_t wallet2::get_approximate_blockchain_height() const @@ -10476,7 +10624,7 @@ size_t wallet2::import_multisig(std::vector<cryptonote::blobdata> blobs) std::string wallet2::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const { crypto::chacha_key key; - crypto::generate_chacha_key(&skey, sizeof(skey), key); + crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds); std::string ciphertext; crypto::chacha_iv iv = crypto::rand<crypto::chacha_iv>(); ciphertext.resize(plaintext.size() + sizeof(iv) + (authenticated ? sizeof(crypto::signature) : 0)); @@ -10506,7 +10654,7 @@ std::string wallet2::decrypt(const std::string &ciphertext, const crypto::secret error::wallet_internal_error, "Unexpected ciphertext size"); crypto::chacha_key key; - crypto::generate_chacha_key(&skey, sizeof(skey), key); + crypto::generate_chacha_key(&skey, sizeof(skey), key, m_kdf_rounds); const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; std::string plaintext; plaintext.resize(ciphertext.size() - prefix_size); @@ -10781,15 +10929,10 @@ std::vector<std::pair<uint64_t, uint64_t>> wallet2::estimate_backlog(const std:: THROW_WALLET_EXCEPTION_IF(res.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_txpool_backlog"); THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error); - cryptonote::COMMAND_RPC_GET_INFO::request req_t = AUTO_VAL_INIT(req_t); - cryptonote::COMMAND_RPC_GET_INFO::response resp_t = AUTO_VAL_INIT(resp_t); - m_daemon_rpc_mutex.lock(); - r = net_utils::invoke_http_json_rpc("/json_rpc", "get_info", req_t, resp_t, m_http_client); - m_daemon_rpc_mutex.unlock(); - THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_info"); - THROW_WALLET_EXCEPTION_IF(resp_t.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "get_info"); - THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_tx_pool_error); - uint64_t full_reward_zone = resp_t.block_size_limit / 2; + uint64_t block_size_limit = 0; + const auto result = m_node_rpc_proxy.get_block_size_limit(block_size_limit); + throw_on_rpc_response_error(result, "get_info"); + uint64_t full_reward_zone = block_size_limit / 2; std::vector<std::pair<uint64_t, uint64_t>> blocks; for (const auto &fee_level: fee_levels) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index d33d8258b..7e67dc4ed 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -165,9 +165,9 @@ namespace tools //! Just parses variables. static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm, const std::function<boost::optional<password_container>(const char *, bool)> &password_prompter); - static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev); + static bool verify_password(const std::string& keys_file_name, const epee::wipeable_string& password, bool no_spend_key, hw::device &hwdev, uint64_t kdf_rounds); - wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false); + wallet2(cryptonote::network_type nettype = cryptonote::MAINNET, bool restricted = false, uint64_t kdf_rounds = 1); ~wallet2(); struct multisig_info @@ -609,7 +609,7 @@ namespace tools /*! * \brief verifies given password is correct for default wallet keys file */ - bool verify_password(const epee::wipeable_string& password) const; + bool verify_password(const epee::wipeable_string& password); cryptonote::account_base& get_account(){return m_account;} const cryptonote::account_base& get_account()const{return m_account;} @@ -925,6 +925,8 @@ namespace tools void key_reuse_mitigation2(bool value) { m_key_reuse_mitigation2 = value; } uint64_t segregation_height() const { return m_segregation_height; } void segregation_height(uint64_t height) { m_segregation_height = height; } + bool ignore_fractional_outputs() const { return m_ignore_fractional_outputs; } + void ignore_fractional_outputs(bool value) { m_ignore_fractional_outputs = value; } bool confirm_non_default_ring_size() const { return m_confirm_non_default_ring_size; } void confirm_non_default_ring_size(bool always) { m_confirm_non_default_ring_size = always; } @@ -1144,6 +1146,9 @@ namespace tools bool unblackball_output(const crypto::public_key &output); bool is_output_blackballed(const crypto::public_key &output) const; + bool lock_keys_file(); + bool unlock_keys_file(); + bool is_keys_file_locked() const; private: /*! * \brief Stores wallet information to wallet file. @@ -1167,7 +1172,7 @@ namespace tools bool clear(); void pull_blocks(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices> &o_indices); void pull_hashes(uint64_t start_height, uint64_t& blocks_start_height, const std::list<crypto::hash> &short_chain_history, std::vector<crypto::hash> &hashes); - void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history); + void fast_refresh(uint64_t stop_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, bool force = false); void pull_and_parse_next_blocks(uint64_t start_height, uint64_t &blocks_start_height, std::list<crypto::hash> &short_chain_history, const std::vector<cryptonote::block_complete_entry> &prev_blocks, const std::vector<parsed_block> &prev_parsed_blocks, std::vector<cryptonote::block_complete_entry> &blocks, std::vector<parsed_block> &parsed_blocks, bool &error); void process_parsed_blocks(uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<parsed_block> &parsed_blocks, uint64_t& blocks_added); uint64_t select_transfers(uint64_t needed_money, std::vector<size_t> unused_transfers_indices, std::vector<size_t>& selected_transfers, bool trusted_daemon) const; @@ -1181,6 +1186,7 @@ namespace tools crypto::hash get_payment_id(const pending_tx &ptx) const; void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const; void check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info) const; + void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const; void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const; uint64_t get_upper_transaction_size_limit() const; std::vector<uint64_t> get_unspent_amounts_vector() const; @@ -1209,7 +1215,7 @@ namespace tools void cache_ringdb_key(); void clear_ringdb_key(); - bool get_output_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution); + bool get_rct_distribution(uint64_t &start_height, std::vector<uint64_t> &distribution); uint64_t get_segregation_fork_height() const; @@ -1252,6 +1258,7 @@ namespace tools bool m_key_on_device; cryptonote::network_type m_nettype; bool m_restricted; + uint64_t m_kdf_rounds; std::string seed_language; /*!< Language of the mnemonics (seed). */ bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ bool m_watch_only; /*!< no spend key */ @@ -1283,6 +1290,7 @@ namespace tools bool m_segregate_pre_fork_outputs; bool m_key_reuse_mitigation2; uint64_t m_segregation_height; + bool m_ignore_fractional_outputs; bool m_is_initialized; NodeRPCProxy m_node_rpc_proxy; std::unordered_set<crypto::hash> m_scanned_pool_txs[2]; diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 214d51cde..e80652750 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -70,6 +70,7 @@ namespace tools // get_out_indexes_error // tx_parse_error // get_tx_pool_error + // out_of_hashchain_bounds_error // transfer_error * // get_random_outs_general_error // not_enough_unlocked_money @@ -398,6 +399,16 @@ namespace tools std::string to_string() const { return refresh_error::to_string(); } }; //---------------------------------------------------------------------------------------------------- + struct out_of_hashchain_bounds_error : public refresh_error + { + explicit out_of_hashchain_bounds_error(std::string&& loc) + : refresh_error(std::move(loc), "Index out of bounds of of hashchain") + { + } + + std::string to_string() const { return refresh_error::to_string(); } + }; + //---------------------------------------------------------------------------------------------------- struct transfer_error : public wallet_logic_error { protected: diff --git a/tests/README.md b/tests/README.md index 48a6c41a7..0bf097254 100644 --- a/tests/README.md +++ b/tests/README.md @@ -50,6 +50,20 @@ To run the same tests on a release build, replace `debug` with `release`. # Functional tests [TODO] +Functional tests are located under the `tests/functional` directory. + +First, run a regtest daemon in the offline mode and with a fixed difficulty: +``` +monerod --regtest --offline --fixed-difficulty 1 +``` +Alternatively, you can run multiple daemons and let them connect with each other by using `--add-exclusive-node`. In this case, make sure that the same fixed difficulty is given to all the daemons. + +Next, restore a mainnet wallet with the following seed and restore height 0 (the file path doesn't matter): +``` +velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted +``` + +Open the wallet file with `monero-wallet-rpc` with RPC port 18083. Finally, start tests by invoking ./blockchain.py or ./speed.py # Fuzz tests diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 201da4fa0..bbc9edd19 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -664,6 +664,7 @@ inline bool do_replay_file(const std::string& filename) } #define GENERATE_AND_PLAY(genclass) \ + if (filter.empty() || boost::regex_match(std::string(#genclass), match, boost::regex(filter))) \ { \ std::vector<test_event_entry> events; \ ++tests_count; \ diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 6a1992cd1..c31655070 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "chaingen_tests_list.h" +#include "common/util.h" #include "common/command_line.h" #include "transaction_tests.h" @@ -42,6 +43,7 @@ namespace const command_line::arg_descriptor<bool> arg_play_test_data = {"play_test_data", ""}; const command_line::arg_descriptor<bool> arg_generate_and_play_test_data = {"generate_and_play_test_data", ""}; const command_line::arg_descriptor<bool> arg_test_transactions = {"test_transactions", ""}; + const command_line::arg_descriptor<std::string> arg_filter = { "filter", "Regular expression filter for which tests to run" }; } int main(int argc, char* argv[]) @@ -61,6 +63,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_options, arg_play_test_data); command_line::add_arg(desc_options, arg_generate_and_play_test_data); command_line::add_arg(desc_options, arg_test_transactions); + command_line::add_arg(desc_options, arg_filter); po::variables_map vm; bool r = command_line::handle_error_helper(desc_options, [&]() @@ -78,6 +81,9 @@ int main(int argc, char* argv[]) return 0; } + const std::string filter = tools::glob_to_regex(command_line::get_arg(vm, arg_filter)); + boost::smatch match; + size_t tests_count = 0; std::vector<std::string> failed_tests; std::string tests_folder = command_line::get_arg(vm, arg_test_data_path); diff --git a/tests/data/fuzz/parse-url/URL2 b/tests/data/fuzz/parse-url/URL2 index b66e7de9a..6eeadc01a 100644 --- a/tests/data/fuzz/parse-url/URL2 +++ b/tests/data/fuzz/parse-url/URL2 @@ -1 +1 @@ -iframe_test.html?api_url=http://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
\ No newline at end of file +iframe_test.html?api_url=https://api.vk.com/api.php&api_id=3289090&api_settings=1&viewer_id=562964060&viewer_type=0&sid=0aad8d1c5713130f9ca0076f2b7b47e532877424961367d81e7fa92455f069be7e21bc3193cbd0be11895&secret=368ebbc0ef&access_token=668bc03f43981d883f73876ffff4aa8564254b359cc745dfa1b3cde7bdab2e94105d8f6d8250717569c0a7&user_id=0&group_id=0&is_app_user=1&auth_key=d2f7a895ca5ff3fdb2a2a8ae23fe679a&language=0&parent_language=0&ad_info=ElsdCQBaQlxiAQRdFUVUXiN2AVBzBx5pU1BXIgZUJlIEAWcgAUoLQg==&referrer=unknown&lc_name=9834b6a3&hash=
\ No newline at end of file diff --git a/tests/functional_tests/blockchain.py b/tests/functional_tests/blockchain.py new file mode 100755 index 000000000..983658a7c --- /dev/null +++ b/tests/functional_tests/blockchain.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2018 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. + +"""Test blockchain RPC calls + +Test the following RPCs: + - get_info + - generateblocks + - [TODO: many tests still need to be written] + +""" + +from test_framework.daemon import Daemon +from test_framework.wallet import Wallet + +class BlockchainTest(): + def run_test(self): + self._test_get_info() + self._test_hardfork_info() + self._test_generateblocks(5) + + def _test_get_info(self): + print('Test get_info') + + daemon = Daemon() + res = daemon.get_info() + + # difficulty should be set to 1 for this test + assert 'difficulty' in res.keys() + assert res['difficulty'] == 1; + + # nettype should not be TESTNET + assert 'testnet' in res.keys() + assert res['testnet'] == False; + + # nettype should not be STAGENET + assert 'stagenet' in res.keys() + assert res['stagenet'] == False; + + # nettype should be FAKECHAIN + assert 'nettype' in res.keys() + assert res['nettype'] == "fakechain"; + + # free_space should be > 0 + assert 'free_space' in res.keys() + assert res['free_space'] > 0 + + # height should be greater or equal to 1 + assert 'height' in res.keys() + assert res['height'] >= 1 + + + def _test_hardfork_info(self): + print('Test hard_fork_info') + + daemon = Daemon() + res = daemon.hard_fork_info() + + # hard_fork version should be set at height 1 + assert 'earliest_height' in res.keys() + assert res['earliest_height'] == 1; + + + def _test_generateblocks(self, blocks): + print("Test generating", blocks, 'blocks') + + daemon = Daemon() + res = daemon.get_info() + height = res['height'] + res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks) + + assert res['height'] == height + blocks - 1 + + +if __name__ == '__main__': + BlockchainTest().run_test() diff --git a/tests/functional_tests/speed.py b/tests/functional_tests/speed.py new file mode 100755 index 000000000..3d2af9a10 --- /dev/null +++ b/tests/functional_tests/speed.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2018 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. + +"""Test speed of various procedures + +Test the following RPCs: + - generateblocks + - transfer + - [TODO: many tests still need to be written] + +""" + + +import time +from time import sleep +from decimal import Decimal + +from test_framework.daemon import Daemon +from test_framework.wallet import Wallet + + +class SpeedTest(): + def set_test_params(self): + self.num_nodes = 1 + + def run_test(self): + daemon = Daemon() + wallet = Wallet() + + destinations = wallet.make_uniform_destinations('44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A',1,3) + + self._test_speed_generateblocks(daemon=daemon, blocks=70) + for i in range(1, 10): + while wallet.get_balance()['unlocked_balance'] == 0: + print('Waiting for wallet to refresh...') + sleep(1) + self._test_speed_transfer_split(wallet=wallet) + self._test_speed_generateblocks(daemon=daemon, blocks=10) + + def _test_speed_generateblocks(self, daemon, blocks): + print('Test speed of block generation') + start = time.time() + + res = daemon.generateblocks('42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm', blocks) + # wallet seed: velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted + + print('generating ', blocks, 'blocks took: ', time.time() - start, 'seconds') + + def _test_speed_transfer_split(self, wallet): + print('Test speed of transfer') + start = time.time() + + destinations = wallet.make_uniform_destinations('44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A',1) + res = wallet.transfer_split(destinations) + + print('generating tx took: ', time.time() - start, 'seconds') + + +if __name__ == '__main__': + SpeedTest().run_test() diff --git a/tests/functional_tests/test_framework/__init__.py b/tests/functional_tests/test_framework/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/functional_tests/test_framework/__init__.py diff --git a/tests/functional_tests/test_framework/daemon.py b/tests/functional_tests/test_framework/daemon.py new file mode 100644 index 000000000..f3490b232 --- /dev/null +++ b/tests/functional_tests/test_framework/daemon.py @@ -0,0 +1,105 @@ +# Copyright (c) 2018 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. + +"""Daemon class to make rpc calls and store state.""" + +from .rpc import JSONRPC + +class Daemon(object): + + def __init__(self, protocol='http', host='127.0.0.1', port=18081, path='/json_rpc'): + self.rpc = JSONRPC('{protocol}://{host}:{port}{path}'.format(protocol=protocol, host=host, port=port, path=path)) + + def getblocktemplate(self, address): + getblocktemplate = { + 'method': 'getblocktemplate', + 'params': { + 'wallet_address': address, + 'reserve_size' : 1 + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(getblocktemplate) + + def submitblock(self, block): + submitblock = { + 'method': 'submitblock', + 'params': [ block ], + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(submitblock) + + def getblock(self, height=0): + getblock = { + 'method': 'getblock', + 'params': { + 'height': height + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(getblock) + + def get_connections(self): + get_connections = { + 'method': 'get_connections', + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(get_connections) + + def get_info(self): + get_info = { + 'method': 'get_info', + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(get_info) + + def hard_fork_info(self): + hard_fork_info = { + 'method': 'hard_fork_info', + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(hard_fork_info) + + def generateblocks(self, address, blocks=1): + generateblocks = { + 'method': 'generateblocks', + 'params': { + 'amount_of_blocks' : blocks, + 'reserve_size' : 20, + 'wallet_address': address + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(generateblocks) diff --git a/tests/functional_tests/test_framework/rpc.py b/tests/functional_tests/test_framework/rpc.py new file mode 100644 index 000000000..b21df7b93 --- /dev/null +++ b/tests/functional_tests/test_framework/rpc.py @@ -0,0 +1,49 @@ +# Copyright (c) 2018 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. + +import requests +import json + +class JSONRPC(object): + def __init__(self, url): + self.url = url + + def send_request(self, inputs): + res = requests.post( + self.url, + data=json.dumps(inputs), + headers={'content-type': 'application/json'}) + res = res.json() + + assert 'error' not in res, res + + return res['result'] + + + + diff --git a/tests/functional_tests/test_framework/wallet.py b/tests/functional_tests/test_framework/wallet.py new file mode 100644 index 000000000..357eab5b2 --- /dev/null +++ b/tests/functional_tests/test_framework/wallet.py @@ -0,0 +1,120 @@ +# Copyright (c) 2018 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. + +"""Daemon class to make rpc calls and store state.""" + +from .rpc import JSONRPC + +class Wallet(object): + + def __init__(self, protocol='http', host='127.0.0.1', port=18083, path='/json_rpc'): + self.rpc = JSONRPC('{protocol}://{host}:{port}{path}'.format(protocol=protocol, host=host, port=port, path=path)) + + def make_uniform_destinations(self, address, transfer_amount, transfer_number_of_destinations=1): + destinations = [] + for i in range(transfer_number_of_destinations): + destinations.append({"amount":transfer_amount,"address":address}) + return destinations + + def make_destinations(self, addresses, transfer_amounts): + destinations = [] + for i in range(len(addresses)): + destinations.append({'amount':transfer_amounts[i],'address':addresses[i]}) + return destinations + + def transfer(self, destinations, ringsize=7, payment_id=''): + transfer = { + 'method': 'transfer', + 'params': { + 'destinations': destinations, + 'mixin' : ringsize - 1, + 'get_tx_key' : True + }, + 'jsonrpc': '2.0', + 'id': '0' + } + if(len(payment_id) > 0): + transfer['params'].update({'payment_id' : payment_id}) + return self.rpc.send_request(transfer) + + def transfer_split(self, destinations, ringsize=7, payment_id=''): + print(destinations) + transfer = { + "method": "transfer_split", + "params": { + "destinations": destinations, + "mixin" : ringsize - 1, + "get_tx_key" : True, + "new_algorithm" : True + }, + "jsonrpc": "2.0", + "id": "0" + } + if(len(payment_id) > 0): + transfer['params'].update({'payment_id' : payment_id}) + return self.rpc.send_request(transfer) + + def create_wallet(self, index=''): + create_wallet = { + 'method': 'create_wallet', + 'params': { + 'filename': 'testWallet' + index, + 'password' : '', + 'language' : 'English' + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(create_wallet) + + def get_balance(self): + get_balance = { + 'method': 'get_balance', + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(get_balance) + + def sweep_dust(self): + sweep_dust = { + 'method': 'sweep_dust', + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(sweep_dust) + + def sweep_all(self, address): + sweep_all = { + 'method': 'sweep_all', + 'params' : { + 'address' : '' + }, + 'jsonrpc': '2.0', + 'id': '0' + } + return self.rpc.send_request(sweep_all) diff --git a/tests/gtest/cmake/internal_utils.cmake b/tests/gtest/cmake/internal_utils.cmake index 567edaa30..ae45d7d7a 100644 --- a/tests/gtest/cmake/internal_utils.cmake +++ b/tests/gtest/cmake/internal_utils.cmake @@ -96,6 +96,10 @@ macro(config_compiler_and_linker) set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0") set(cxx_strict_flags "-Wextra -Wno-unused-parameter -Wno-missing-field-initializers") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(cxx_base_flags "-Wall -Wshadow -fPIC") + set(cxx_exception_flags "-fexceptions") + set(cxx_no_exception_flags "-fno-exceptions") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") set(cxx_exception_flags "-features=except") # Sun Pro doesn't provide macros to indicate whether exceptions and diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 902bd89c0..bc3622ea8 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -54,25 +54,6 @@ namespace po = boost::program_options; -std::string glob_to_regex(const std::string &val) -{ - std::string newval; - - bool escape = false; - for (char c: val) - { - if (c == '*') - newval += escape ? "*" : ".*"; - else if (c == '?') - newval += escape ? "?" : "."; - else if (c == '\\') - newval += '\\', escape = !escape; - else - newval += c; - } - return newval; -} - int main(int argc, char** argv) { TRY_ENTRY(); @@ -97,7 +78,7 @@ int main(int argc, char** argv) if (!r) return 1; - const std::string filter = glob_to_regex(command_line::get_arg(vm, arg_filter)); + const std::string filter = tools::glob_to_regex(command_line::get_arg(vm, arg_filter)); performance_timer timer; timer.start(); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 6d79ba74b..3c7414640 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -41,6 +41,7 @@ set(unit_tests_sources command_line.cpp crypto.cpp decompose_amount_into_digits.cpp + device.cpp dns_resolver.cpp epee_boosted_tcp_server.cpp epee_levin_protocol_handler_async.cpp @@ -55,6 +56,7 @@ set(unit_tests_sources mul_div.cpp multisig.cpp parse_amount.cpp + random.cpp serialization.cpp sha256.cpp slow_memmem.cpp @@ -88,7 +90,6 @@ target_link_libraries(unit_tests wallet p2p version - epee ${Boost_CHRONO_LIBRARY} ${Boost_THREAD_LIBRARY} ${GTEST_LIBRARIES} diff --git a/tests/unit_tests/device.cpp b/tests/unit_tests/device.cpp new file mode 100644 index 000000000..50ccec9fa --- /dev/null +++ b/tests/unit_tests/device.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 2018, 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. + +#include "gtest/gtest.h" +#include "ringct/rctOps.h" +#include "device/device_default.hpp" + +TEST(device, name) +{ + hw::core::device_default dev; + ASSERT_TRUE(dev.set_name("test")); + ASSERT_EQ(dev.get_name(), "test"); +} + +/* +TEST(device, locking) +{ + hw::core::device_default dev; + ASSERT_TRUE(dev.try_lock()); + ASSERT_FALSE(dev.try_lock()); + dev.unlock(); + ASSERT_TRUE(dev.try_lock()); + dev.unlock(); + dev.lock(); + ASSERT_FALSE(dev.try_lock()); + dev.unlock(); + ASSERT_TRUE(dev.try_lock()); + dev.unlock(); +} +*/ + +TEST(device, open_close) +{ + hw::core::device_default dev; + crypto::secret_key key; + ASSERT_TRUE(dev.open_tx(key)); + ASSERT_TRUE(dev.close_tx()); +} + +TEST(device, ops) +{ + hw::core::device_default dev; + rct::key resd, res; + crypto::key_derivation derd, der; + rct::key sk, pk; + crypto::secret_key sk0, sk1; + crypto::public_key pk0, pk1; + crypto::ec_scalar ressc0, ressc1; + crypto::key_image ki0, ki1; + + rct::skpkGen(sk, pk); + rct::scalarmultBase((rct::key&)pk0, (rct::key&)sk0); + rct::scalarmultBase((rct::key&)pk1, (rct::key&)sk1); + + dev.scalarmultKey(resd, pk, sk); + rct::scalarmultKey(res, pk, sk); + ASSERT_EQ(resd, res); + + dev.scalarmultBase(resd, sk); + rct::scalarmultBase(res, sk); + ASSERT_EQ(resd, res); + + dev.sc_secret_add((crypto::secret_key&)resd, sk0, sk1); + sc_add((unsigned char*)&res, (unsigned char*)&sk0, (unsigned char*)&sk1); + ASSERT_EQ(resd, res); + + dev.generate_key_derivation(pk0, sk0, derd); + crypto::generate_key_derivation(pk0, sk0, der); + ASSERT_FALSE(memcmp(&derd, &der, sizeof(der))); + + dev.derivation_to_scalar(der, 0, ressc0); + crypto::derivation_to_scalar(der, 0, ressc1); + ASSERT_FALSE(memcmp(&ressc0, &ressc1, sizeof(ressc1))); + + dev.derive_secret_key(der, 0, rct::rct2sk(sk), sk0); + crypto::derive_secret_key(der, 0, rct::rct2sk(sk), sk1); + ASSERT_EQ(sk0, sk1); + + dev.derive_public_key(der, 0, rct::rct2pk(pk), pk0); + crypto::derive_public_key(der, 0, rct::rct2pk(pk), pk1); + ASSERT_EQ(pk0, pk1); + + dev.secret_key_to_public_key(rct::rct2sk(sk), pk0); + crypto::secret_key_to_public_key(rct::rct2sk(sk), pk1); + ASSERT_EQ(pk0, pk1); + + dev.generate_key_image(pk0, sk0, ki0); + crypto::generate_key_image(pk0, sk0, ki1); + ASSERT_EQ(ki0, ki1); +} + +TEST(device, ecdh) +{ + hw::core::device_default dev; + rct::ecdhTuple tuple, tuple2; + rct::key key = rct::skGen(); + tuple.mask = rct::skGen(); + tuple.amount = rct::skGen(); + tuple.senderPk = rct::pkGen(); + tuple2 = tuple; + dev.ecdhEncode(tuple, key); + dev.ecdhDecode(tuple, key); + ASSERT_EQ(tuple2.mask, tuple.mask); + ASSERT_EQ(tuple2.amount, tuple.amount); + ASSERT_EQ(tuple2.senderPk, tuple.senderPk); +} diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index 913ebe84a..930aeb782 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -50,6 +50,7 @@ public: virtual void safesyncmode(const bool onoff) {} virtual void reset() {} virtual std::vector<std::string> get_filenames() const { return std::vector<std::string>(); } + virtual bool remove_data_file(const std::string& folder) const { return true; } virtual std::string get_db_name() const { return std::string(); } virtual bool lock() { return true; } virtual void unlock() { } @@ -69,6 +70,7 @@ public: virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; } virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); } virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; } + virtual std::vector<uint64_t> get_block_cumulative_rct_outputs(const std::vector<uint64_t> &heights) const { return {}; } virtual uint64_t get_top_block_timestamp() const { return 0; } virtual size_t get_block_size(const uint64_t& height) const { return 128; } virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; } @@ -124,6 +126,7 @@ public: virtual void remove_txpool_tx(const crypto::hash& txid) {} virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; } virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } + virtual uint64_t get_database_size() const { return 0; } virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } virtual bool for_all_txpool_txes(std::function<bool(const crypto::hash&, const txpool_tx_meta_t&, const cryptonote::blobdata*)>, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; } @@ -131,6 +134,7 @@ public: , const size_t& block_size , const difficulty_type& cumulative_difficulty , const uint64_t& coins_generated + , uint64_t num_rct_outs , const crypto::hash& blk_hash ) { blocks.push_back(blk); @@ -183,20 +187,20 @@ TEST(major, Only) ASSERT_FALSE(hf.add(mkblock(0, 2), 0)); ASSERT_FALSE(hf.add(mkblock(2, 2), 0)); ASSERT_TRUE(hf.add(mkblock(1, 2), 0)); - db.add_block(mkblock(1, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(1, 1), 0, 0, 0, 0, crypto::hash()); // block height 1, only version 1 is accepted ASSERT_FALSE(hf.add(mkblock(0, 2), 1)); ASSERT_FALSE(hf.add(mkblock(2, 2), 1)); ASSERT_TRUE(hf.add(mkblock(1, 2), 1)); - db.add_block(mkblock(1, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(1, 1), 0, 0, 0, 0, crypto::hash()); // block height 2, only version 2 is accepted ASSERT_FALSE(hf.add(mkblock(0, 2), 2)); ASSERT_FALSE(hf.add(mkblock(1, 2), 2)); ASSERT_FALSE(hf.add(mkblock(3, 2), 2)); ASSERT_TRUE(hf.add(mkblock(2, 2), 2)); - db.add_block(mkblock(2, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(2, 1), 0, 0, 0, 0, crypto::hash()); } TEST(empty_hardforks, Success) @@ -210,7 +214,7 @@ TEST(empty_hardforks, Success) ASSERT_TRUE(hf.get_state(time(NULL) + 3600*24*400) == HardFork::Ready); for (uint64_t h = 0; h <= 10; ++h) { - db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } ASSERT_EQ(hf.get(0), 1); @@ -244,14 +248,14 @@ TEST(check_for_height, Success) for (uint64_t h = 0; h <= 4; ++h) { ASSERT_TRUE(hf.check_for_height(mkblock(1, 1), h)); ASSERT_FALSE(hf.check_for_height(mkblock(2, 2), h)); // block version is too high - db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } for (uint64_t h = 5; h <= 10; ++h) { ASSERT_FALSE(hf.check_for_height(mkblock(1, 1), h)); // block version is too low ASSERT_TRUE(hf.check_for_height(mkblock(2, 2), h)); - db.add_block(mkblock(hf, h, 2), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } } @@ -268,19 +272,19 @@ TEST(get, next_version) for (uint64_t h = 0; h <= 4; ++h) { ASSERT_EQ(2, hf.get_next_version()); - db.add_block(mkblock(hf, h, 1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 1), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } for (uint64_t h = 5; h <= 9; ++h) { ASSERT_EQ(4, hf.get_next_version()); - db.add_block(mkblock(hf, h, 2), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 2), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } for (uint64_t h = 10; h <= 15; ++h) { ASSERT_EQ(4, hf.get_next_version()); - db.add_block(mkblock(hf, h, 4), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 4), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } } @@ -321,7 +325,7 @@ TEST(steps_asap, Success) hf.init(); for (uint64_t h = 0; h < 10; ++h) { - db.add_block(mkblock(hf, h, 9), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, 9), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } @@ -348,7 +352,7 @@ TEST(steps_1, Success) hf.init(); for (uint64_t h = 0 ; h < 10; ++h) { - db.add_block(mkblock(hf, h, h+1), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, h+1), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } @@ -373,7 +377,7 @@ TEST(reorganize, Same) // index 0 1 2 3 4 5 6 7 8 9 static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; for (uint64_t h = 0; h < 20; ++h) { - db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } @@ -404,7 +408,7 @@ TEST(reorganize, Changed) static const uint8_t block_versions[] = { 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }; static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 1, 4, 4, 7, 7, 9, 9, 9, 9, 9, 9 }; for (uint64_t h = 0; h < 16; ++h) { - db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE (hf.add(db.get_block_from_height(h), h)); } @@ -424,7 +428,7 @@ TEST(reorganize, Changed) ASSERT_EQ(db.height(), 3); hf.reorganize_from_block_height(2); for (uint64_t h = 3; h < 16; ++h) { - db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, block_versions_new[h]), 0, 0, 0, 0, crypto::hash()); bool ret = hf.add(db.get_block_from_height(h), h); ASSERT_EQ (ret, h < 15); } @@ -448,7 +452,7 @@ TEST(voting, threshold) for (uint64_t h = 0; h <= 8; ++h) { uint8_t v = 1 + !!(h % 8); - db.add_block(mkblock(hf, h, v), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, v), 0, 0, 0, 0, crypto::hash()); bool ret = hf.add(db.get_block_from_height(h), h); if (h >= 8 && threshold == 87) { // for threshold 87, we reach the treshold at height 7, so from height 8, hard fork to version 2, but 8 tries to add 1 @@ -482,7 +486,7 @@ TEST(voting, different_thresholds) static const uint8_t expected_versions[] = { 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 }; for (uint64_t h = 0; h < sizeof(block_versions) / sizeof(block_versions[0]); ++h) { - db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash()); bool ret = hf.add(db.get_block_from_height(h), h); ASSERT_EQ(ret, true); } @@ -536,7 +540,7 @@ TEST(voting, info) ASSERT_EQ(expected_thresholds[h], threshold); ASSERT_EQ(4, voting); - db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, crypto::hash()); + db.add_block(mkblock(hf, h, block_versions[h]), 0, 0, 0, 0, crypto::hash()); ASSERT_TRUE(hf.add(db.get_block_from_height(h), h)); } } @@ -599,7 +603,7 @@ TEST(reorganize, changed) #define ADD(v, h, a) \ do { \ cryptonote::block b = mkblock(hf, h, v); \ - db.add_block(b, 0, 0, 0, crypto::hash()); \ + db.add_block(b, 0, 0, 0, 0, crypto::hash()); \ ASSERT_##a(hf.add(b, h)); \ } while(0) #define ADD_TRUE(v, h) ADD(v, h, TRUE) diff --git a/tests/unit_tests/random.cpp b/tests/unit_tests/random.cpp new file mode 100644 index 000000000..7653453cd --- /dev/null +++ b/tests/unit_tests/random.cpp @@ -0,0 +1,47 @@ +// Copyright (c) 2018, 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. + +#include "gtest/gtest.h" + +#include "crypto/crypto.h" + +extern "C" { +#include "crypto/crypto-ops.h" +} + +TEST(random32_unbiased, less_than_order) +{ + unsigned char tmp[32], tmp2[32]; + for (int i = 0; i < 1000; ++i) + { + crypto::random32_unbiased(tmp); + memcpy(tmp2, tmp, 32); + sc_reduce32(tmp2); + ASSERT_EQ(memcmp(tmp, tmp2, 32), 0); + } +} diff --git a/tests/unit_tests/ringct.cpp b/tests/unit_tests/ringct.cpp index 0f4bd3edf..6e3958f8a 100644 --- a/tests/unit_tests/ringct.cpp +++ b/tests/unit_tests/ringct.cpp @@ -957,12 +957,20 @@ TEST(ringct, fee_burn_valid_zero_out_simple) EXPECT_TRUE(range_proof_test(true, NELTS(inputs), inputs, NELTS(outputs), outputs, true, true)); } +static rctSig make_sig() +{ + static const uint64_t inputs[] = {1000, 1000}; + static const uint64_t outputs[] = {1000, 1000}; + static rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); + return sig; +} + #define TEST_rctSig_elements(name, op) \ TEST(ringct, rctSig_##name) \ { \ const uint64_t inputs[] = {1000, 1000}; \ const uint64_t outputs[] = {1000, 1000}; \ - rct::rctSig sig = make_sample_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, true); \ + rct::rctSig sig = make_sig(); \ ASSERT_TRUE(rct::verRct(sig)); \ op; \ ASSERT_FALSE(rct::verRct(sig)); \ @@ -994,12 +1002,18 @@ TEST_rctSig_elements(outPk_empty, sig.outPk.resize(0)); TEST_rctSig_elements(outPk_too_many, sig.outPk.push_back(sig.outPk.back())); TEST_rctSig_elements(outPk_too_few, sig.outPk.pop_back()); +static rct::rctSig make_sig_simple() +{ + static const uint64_t inputs[] = {1000, 1000}; + static const uint64_t outputs[] = {1000}; + static rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000); + return sig; +} + #define TEST_rctSig_elements_simple(name, op) \ TEST(ringct, rctSig_##name##_simple) \ { \ - const uint64_t inputs[] = {1000, 1000}; \ - const uint64_t outputs[] = {1000}; \ - rct::rctSig sig = make_sample_simple_rct_sig(NELTS(inputs), inputs, NELTS(outputs), outputs, 1000); \ + rct::rctSig sig = make_sig_simple(); \ ASSERT_TRUE(rct::verRctSimple(sig)); \ op; \ ASSERT_FALSE(rct::verRctSimple(sig)); \ diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 5a2114027..40616059a 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -810,7 +810,7 @@ TEST(Serialization, portability_outputs) if(ciphertext.size() < prefix_size) return {}; crypto::chacha_key key; - crypto::generate_chacha_key(&skey, sizeof(skey), key); + crypto::generate_chacha_key(&skey, sizeof(skey), key, 1); const crypto::chacha_iv &iv = *(const crypto::chacha_iv*)&ciphertext[0]; std::string plaintext; plaintext.resize(ciphertext.size() - prefix_size); diff --git a/utils/build_scripts/android32.Dockerfile b/utils/build_scripts/android32.Dockerfile index 20b846aa1..d0d25aa3d 100644 --- a/utils/build_scripts/android32.Dockerfile +++ b/utils/build_scripts/android32.Dockerfile @@ -4,7 +4,7 @@ RUN apt-get update && apt-get install -y unzip automake build-essential curl fil WORKDIR /opt/android ## INSTALL ANDROID SDK -RUN curl -s -O http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz \ +RUN curl -s -O https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz \ && tar --no-same-owner -xzf android-sdk_r24.4.1-linux.tgz \ && rm -f android-sdk_r24.4.1-linux.tgz @@ -51,7 +51,7 @@ ENV PATH /usr/cmake-${CMAKE_VERSION}-Linux-x86_64/bin:$PATH # download, configure and make Zlib ENV ZLIB_VERSION 1.2.11 -RUN curl -s -O http://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \ +RUN curl -s -O https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \ && tar -xzf zlib-${ZLIB_VERSION}.tar.gz \ && rm zlib-${ZLIB_VERSION}.tar.gz \ && mv zlib-${ZLIB_VERSION} zlib \ diff --git a/utils/build_scripts/android64.Dockerfile b/utils/build_scripts/android64.Dockerfile index 83bcbad89..a9504fd2c 100644 --- a/utils/build_scripts/android64.Dockerfile +++ b/utils/build_scripts/android64.Dockerfile @@ -4,7 +4,7 @@ RUN apt-get update && apt-get install -y unzip automake build-essential curl fil WORKDIR /opt/android ## INSTALL ANDROID SDK -RUN curl -s -O http://dl.google.com/android/android-sdk_r24.4.1-linux.tgz \ +RUN curl -s -O https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz \ && tar --no-same-owner -xzf android-sdk_r24.4.1-linux.tgz \ && rm -f android-sdk_r24.4.1-linux.tgz @@ -51,7 +51,7 @@ ENV PATH /usr/cmake-${CMAKE_VERSION}-Linux-x86_64/bin:$PATH # download, configure and make Zlib ENV ZLIB_VERSION 1.2.11 -RUN curl -s -O http://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \ +RUN curl -s -O https://zlib.net/zlib-${ZLIB_VERSION}.tar.gz \ && tar -xzf zlib-${ZLIB_VERSION}.tar.gz \ && rm zlib-${ZLIB_VERSION}.tar.gz \ && mv zlib-${ZLIB_VERSION} zlib \ |